Warm tip: This article is reproduced from serverfault.com, please click

SpringBootTest

发布于 2021-01-06 20:25:17

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.

 

Questioner
B Randall
Viewed
0
Gary Russell 2021-01-08 00:17:46
  • 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.