Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
252 views
in Technique[技术] by (71.8m points)

spring - SpringBootTest - How to modify DefaultMessageListenerContainer in integration test

Running with Spring Boot v2.3.4.RELEASE, Spring v5.2.9.RELEASE, JUnit5, IBM MQ

I am writing an integration @SpringBootTest that tests a MessageListener.

The test creates random named queues in order to keep build pipeline distinct. Currently the @BeforeAll Tests creates these queues and attempts to modify the Destination Name in the DefaultMessageListenerContainer Bean. It appears you can't do this before all tests since the spring container has already created the MessageListnerContainer and ignores a change in the container.


@EnableJms

@Configuration

public class JmsConfig {

 

    @Autowired

    private Environment env;

   

    @Value("${inbound-queue}")

    private String inboundQueue;

 

    @Bean

    public MQConnectionFactory mqConnectionFactory() throws JMSException {

        MQConnectionFactory connectionFactory = new MQConnectionFactory();

        connectionFactory.setHostName(env.getProperty("mq.hostname")); //mq host name

        connectionFactory.setPort( Integer.parseInt(env.getProperty("mq.port"))); // mq port

        connectionFactory.setQueueManager(env.getProperty("mq.manager")); //mq queue manager

        connectionFactory.setChannel(env.getProperty("mq.channel")); //mq channel name

        connectionFactory.setTransportType(1); //WMQConstants.WMQ_CM_CLIENT

        return connectionFactory;

    }

 

    @Bean

    public DefaultMessageListenerContainer mqMessageEventContainer() throws JMSException {

        DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();

        container.setAutoStartup(true);

        container.setConnectionFactory(mqConnectionFactory());

        container.setDestinationName(inboundQueue);

        container.setMessageListener(new NotificationListener());

        return container;

    }

Listener:


@Slf4j

public class NotificationListener implements MessageListener {

 

    @Override

    @Transactional()

    public void onMessage(Message msg) {

        log.debug("Received a {}", msg.getClass().getSimpleName());

        try {

            if (msg instanceof JMSObjectMessage) {

                JMSObjectMessage bmrMsg = (JMSObjectMessage) msg;

                log.debug("bmrMsg is a " + bmrMsg.getObject().getClass().getSimpleName());

The test:


    @Autowired

    private JmsConfig jmsConfig;

    @BeforeAll

    public void beforeAllTests(TestInfo testInfo) {

        log.info(START_TEST + testInfo.getTestMethod());

        buildTempQueues();

        log.info(END_TEST + testInfo.getTestMethod());

    }

 

    private void buildTempQueues() {

        assertThat(qHost).isNotNull();

        assertThat(qPortString).isNotNull();

        assertThat(qMgr).isNotNull();

        assertThat(qChannel).isNotNull();

        buildTempQueues(qHost, qPortString, qMgr, qChannel);

 

        Optional<String> qOpt = getQueueName(INBOUND_QUEUE_ENDING);

        if (qOpt.isPresent()) {

            String ibQueue = qOpt.get();

            ReflectionTestUtils.setField(jmsConfig, "inboundQueue", ibQueue);

            try {

                jmsConfig.mqMessageEventContainer().setDestinationName(ibQueue);

            } catch (JMSException e) {

                fail(e.getMessage());

            }

        } else {

            fail("COULD NOT CONFIGURE QUEUES FOR TESTING");

        }

 

        qOpt = getQueueName(FAILURE_QUEUE_ENDING);

        if (qOpt.isPresent()) {

            ReflectionTestUtils.setField(jmsService, "failureQueue", qOpt.get());

        }

    }

 

jmsConfig.mqMessageEventContainer().setDestinationName(ibQueue);

 

 

So jmsConfig.mqMessageEventContainer().setDestinationName(ibQueue); does not appear to change the Bean since the Spring context has already created the listener....


        final CountDownLatch latch = new CountDownLatch(1);

        Executor executor = Executors.newSingleThreadExecutor();

        executor.execute(() -> {

            try {

 

                //then

                jmsTemplate.convertAndSend(getQueueName(INBOUND_QUEUE_ENDING).get(), givenScript.getSubject());

                PCFMessage[] responses = getQueueDepth(qHost, qPortString, qMgr, qChannel, INBOUND_QUEUE_ENDING);

                assertThat(responses).isNotNull();

                for (PCFMessage response : responses) {

                    assertThat(0).isEqualTo(response.getCompCode());

                    assertThat(getQueueName(INBOUND_QUEUE_ENDING).get()).isEqualTo(trim(response.getStringParameterValue(MQConstants.MQCA_Q_NAME)));

                    assertThat(1).isEqualTo(response.getIntParameterValue(MQConstants.MQIA_CURRENT_Q_DEPTH));

                }

 

                while (notificationService.getMsgCt() == 0) {

                    Thread.sleep(2000);

                    log.debug("Messages processed = " + notificationService.getMsgCt());

                }

 

                // now signal that our background task completed

                latch.countDown();

 

            } catch (JmsException | PCFException | InterruptedException e) {

                fail(e.getMessage());

            }

        });

 

        log.info("(T) waiting on latch...");

        try {

            // Block the test thread for at most 5 seconds before giving up and failing the test.

            boolean receivedSignal = latch.await(15, TimeUnit.SECONDS);

            log.info(String.format("(T) Test thread did wait on latch (timeout=%b)", !receivedSignal));

            assertThat(receivedSignal).isTrue();

 

            //TODO Test outboud queue has depth 1

        } catch (InterruptedException e) {

            fail(e.getMessage());

        }

LOGS:


12:42:49.876 [main] INFO  g.d.t.v.v.v.s.i.NotificationListenerTests.whenOnMessage_givenMessageOnQueue_thenProcessMessage -  (T) waiting on latch...

 

12:42:52.102 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:42:54.102 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:42:56.103 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:42:58.103 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:43:00.103 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:43:02.104 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:43:04.105 [pool-3-thread-1] DEBUG g.d.t.v.v.v.s.i.NotificationListenerTests.lambda$whenOnMessage_givenMessageOnQueue_thenProcessMessage$0 -  Messages processed = 0

 

12:43:04.879 [main] INFO  g.d.t.v.v.v.s.i.NotificationListenerTests.whenOnMessage_givenMessageOnQueue_thenProcessMessage -  (T) Test thread did wait on latch (timeout=true)

 

ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 33.779 s <<< FAILURE! - in gov.dhs.tsa.vcs.vet.vcsn.service.impl.NotificationListenerTests

[ERROR] whenOnMessage_givenMessageOnQueue_thenProcessMessage{TestInfo}  Time elapsed: 15.723 s  <<< FAILURE!

org.opentest4j.AssertionFailedError:

 

Expecting:

<false>

to be equal to:

<true>

but was not.

 

question from:https://stackoverflow.com/questions/65602919/springboottest-how-to-modify-defaultmessagelistenercontainer-in-integration-te

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
  • Set autoStartup to false on the listener container.

  • Auto wire the container into the test case and set its destination; then start() the container.

  • you don't need that reflection stuff - it's too late.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...