0

I have the following publishing class.

@Component
public class Publisher {

    @Autowired
    private MessageChannel publishingChannel;

    @Override
    public void publish(Event event) {
        publishingChannel.send(event);
    }
}

I have the following test class.

@RunWith(SpringRunner.class)
@SpringBootTest
public class PublisherTest {

    private final List<Event> events = new ArrayList<>();

    @Autowired
    private Publisher publisher;

    @Test
    public void testPublish() {
        Event testEvent = new Event("some_id_number");
        publisher.publish(testEvent);

        Awaitility.await()
             .atMost(2, TimeUnit.SECONDS)
             .until(() -> !this.events.isEmpty());
    }

    @ServiceActivator(inputChannel = "publishingChannel")
    public void publishEventListener(Event event) {
        this.events.add(event);
    }
}

The message channel bean is instantiated elsewhere. The publisher runs as expected and an event is publishing to the channel, however the service activator is never invoked. What am I missing here?

reka18
  • 7,440
  • 5
  • 16
  • 37

1 Answers1

0

Turns out you need to move the service activator to a separate test component class (@TestComponent prevents this from being injected outside the test context).

@TestComponent
public class TestListener {

    public final List<Object> results = new ArrayList<>();

    @ServiceActivator(inputChannel = "messageChannel")
    public void listener(Event event) {
        Object id = event.getHeaders().get("myId");
        results.add(id);
    }
}

Then you can bring this listener into your test. Make sure you use @Import to bring your service activator class into the test context.

@SpringBootTest
@Import(TestListener.class)
class PublisherTest {

    @Autowired
    private Publisher publisher;

    @Autowired
    private TestListener testListener;

    @Test
    void testPublish() {
        this.publisher.publish(new Event().addHeader("myId", 1));

        Awaitility.await()
            .atMost(2, TimeUnit.SECONDS)
            .until(() -> !this.testListeners.results.isEmpty());
    }
}

The test passes after making these changes. Figured this out with a demo app and applied it to a production testing issue.

reka18
  • 7,440
  • 5
  • 16
  • 37