Search code examples
javaspringspring-integrationspring-jmsspring-boot-test

How to write test my service activator which has input channel and output channel


I am trying to write a small test to test if the message arrived at the input channel is processed to the output channel as written in my listener code? Any comments on how can I start?

Update: I have added XML and test class could you please help me guide on how to write the test for this? Do i need to add the channel Interceptor in the test config class or in the same test class where I add the test method?

 

@Override
    @ServiceActivator(inputChannel = "inChannel", outputChannel = "outChannel")
    public Message<String> receiveEvent(Message<String> receivedEvent) {
        return receivedEvent;
    }

===========================================================

**This is my jms-gateway.xml for the inbound gateway of JMS**



<?xml version="1.0" encoding="UTF-8"?>
        <beans:beans xmlns="http://www.springframework.org/schema/integration"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:beans="http://www.springframework.org/schema/beans"
                     xmlns:context="http://www.springframework.org/schema/context"
                     xmlns:jms="http://www.springframework.org/schema/integration/jms"
                     xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context.xsd
                    http://www.springframework.org/schema/integration
                    http://www.springframework.org/schema/integration/spring-integration.xsd
                    http://www.springframework.org/schema/integration/jms
                    http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
        
            <context:component-scan base-package="com.notification.application" />
        
            <jms:inbound-gateway id="inboundGateway"
                                 request-destination="inQueue"
                                 error-channel="errorChannel"
                                 request-channel="inChannel"
                                 connection-factory="queueConnectionFactory"/>
        
        </beans:beans>

================================================================================================================================================

This is my Test class which I want to have test of my service activator to make sure message reach these channels

@RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:jms-gateway.xml")
    @DirtiesContext
    @SpringBootTest
    public class EventListenerTest {
    
        @Autowired
        @Qualifier("inChannel")
        private DirectChannel messageChannel;
    
        @MockBean
        private EventListenerClass eventListener;
    
        @Before
        public void config() {
        //how to do ?
            messageChannel.addInterceptor();
    
        }
    
        @Test
        void messageReceived_Test() {
            Message<String> message = MessageBuilder.withPayload("Hello").build();
            
            messageChannel.send(message);
    
            Mockito.when(eventListener.receiveEvent(message)).thenReturn(message);
    
            //how to do assertion on interceptor?
            Assertions.assertThat(actualMessage).isNotNull();
        }
    
    }

Solution

  • In your test case, add a ChannelInterceptor to each of the channels and you can verify the intercepted messages.

    EDIT

    Something like this:

    @Test
    void test(@Autowired AbstractMessageChannel inChannel, 
            @Autowired AbstractMessageChannel outChannel) throws InterruptedException {
    
        AtomicReference<Message<?>> inMessage = new AtomicReference<>();
        inChannel.addInterceptor(new ChannelInterceptor() {
    
            @Override
            @Nullable
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                inMessage.set(message);
                return message;
            }
        });
        AtomicReference<Message<?>> outMessage = new AtomicReference<>();
        CountDownLatch latch = new CountDownLatch(1);
        outChannel.addInterceptor(new ChannelInterceptor() {
    
            @Override
            @Nullable
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                outMessage.set(message);
                latch.countDown();
                return message;
            }
        });
    
        // send test message to JMS (or directly to inChannel for a unit test)
        assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
        // verify inMessage.get() is as expected
        // verify outMessage.get() is as expected
    }
    

    This assumes JUnit5; if you are using JUnit4, auto wire the channels as fields in the test instead.

    EDIT2

    Here is the complete app; works fine for me.

    @SpringBootApplication
    public class So71942436Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So71942436Application.class, args);
        }
    
        @ServiceActivator(inputChannel = "inChannel", outputChannel = "outChannel")
        public Message<?> handle(Message<?> msg) {
            return msg;
        }
    
        @ServiceActivator(inputChannel = "outChannel")
        public void dump(Message<?> msg) {
            System.out.println(msg);
        }
    
    }
    
    @SpringBootTest
    class So71942436ApplicationTests {
    
        @Test
        void test(@Autowired AbstractMessageChannel inChannel,
                @Autowired AbstractMessageChannel outChannel) throws InterruptedException {
    
            AtomicReference<Message<?>> inMessage = new AtomicReference<>();
            inChannel.addInterceptor(new ChannelInterceptor() {
    
                @Override
                @Nullable
                public Message<?> preSend(Message<?> message, MessageChannel channel) {
                    inMessage.set(message);
                    return message;
                }
            });
            AtomicReference<Message<?>> outMessage = new AtomicReference<>();
            CountDownLatch latch = new CountDownLatch(1);
            outChannel.addInterceptor(new ChannelInterceptor() {
    
                @Override
                @Nullable
                public Message<?> preSend(Message<?> message, MessageChannel channel) {
                    outMessage.set(message);
                    latch.countDown();
                    return message;
                }
            });
    
            inChannel.send(new GenericMessage<>("foo"));
            // send test message to JMS
            assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
            // verify inMessage.get() is as expected
            // verify outMessage.get() is as expected
        }
    
    }
    

    Test is green.