为什么我的mockbeans和mockrestserviceserver在springboot中测试jms侦听器时没有返回正确的响应

oprakyz7  于 2021-07-22  发布在  Java
关注(0)|答案(1)|浏览(245)

我在尝试集成测试jms侦听器时遇到了一个问题 Mockito 以及 MockRestServiceServer . 即使我用的是正确的 Mockito.when 注解,它们将显示为null MockRestServiceServer 就好像没人叫它一样。如果我改为测试 myService jms侦听器调用的组件、mock和 MockRestServiceServer 电话工作如预期,这是令人费解的。我正在连接到一个嵌入式activemq代理进行测试,如果有帮助的话,我将使用springboot2.2.8.release和jdk8.x。
下面是jms侦听器类

@Component
public class MyJmsListener {

    @Autowired
    private MyService myService;

    @JmsListener(
            destination = "${jms.queue}",
            containerFactory = "myJmsListenerContainerFactory"
    )
    public void receive(Message<String> message) {
        myService.process(message);
    }
}

下面是jms侦听器测试类

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class JmsListenerTest {
...
    @MockBean
    private AuthorizationService authorizationService;
...
    @Autowired
    private MockRestServiceServer mockRestServiceServer;

    @Autowired
    private JmsTemplate listenerTestJmsTemplate;

    @Value("${jms.queue}")
    private String testDestination;
...
   @Test
    public void testListener() throws IOException, URISyntaxException, InterruptedException {
        //ARRANGE
        String payloadPath = "classpath:payloads/listenerPayload.json";
        String payload = new String(Files.readAllBytes(ResourceUtils.getFile(payloadPath).toPath()));
        String testAuth = "auth";
        Mockito.when(authorizationService.generateTicket(Mockito.any(Headers.class), Mockito.eq("9130353887051456")))
                .thenReturn(testAuth);
        String extPayloadPath = "classpath:payloads/revokeCancelAutoRenewRequestApi.json";
        String extPayload = new String(Files.readAllBytes(ResourceUtils.getFile(extPayloadPath).toPath()));
        mockRestServiceServer.expect(ExpectedCount.once(), MockRestRequestMatchers.requestTo(new URI("/test/v3/subscriptions/400367048/something")))
                             .andExpect(MockRestRequestMatchers.content().string(extPayload))
                             .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, testAuth))
                             .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK));
        //ACT
        listenerTestJmsTemplate.convertAndSend(testDestination, payload);
        //ASSERT
        mockRestServiceServer.verify();
        Assert.assertTrue(JmsListenerWrapperConfiguration.latch.await(5, TimeUnit.SECONDS));
    }
...
}

我有一个jmslistenerwrapperconfiguration,它允许我将倒计时锁存器 Package 到jms侦听器中。

@Configuration
@Profile("test")
public class JmsListenerWrapperConfiguration {

    public static final CountDownLatch latch = new CountDownLatch(1);

    @Bean
    public JmsTemplate listenerTestjmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory){
        JmsTemplate jmsTemplate = new JmsTemplate(activeMQConnectionFactory);
        return jmsTemplate;
    }

    /**
     * Wrap the JMS Listeners with a count down latch that will allow us to unit test them.
     * @return The bean post processor that will wrap the JMS Listener.
     */
    @Bean
    public static BeanPostProcessor listenerWrapper() {
        return new BeanPostProcessor() {

            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof MyJmsListener) {
                    MethodInterceptor interceptor = new MethodInterceptor() {

                        @Override
                        public Object invoke(MethodInvocation invocation) throws Throwable {
                            Object result = invocation.proceed();
                            if (invocation.getMethod().getName().equals("listen")) {
                                latch.countDown();
                            }
                            return result;
                        }

                    };
                    if (AopUtils.isAopProxy(bean)) {
                        ((Advised) bean).addAdvice(interceptor);
                        return bean;
                    }
                    else {
                        ProxyFactory proxyFactory = new ProxyFactory(bean);
                        proxyFactory.addAdvice(interceptor);
                        return proxyFactory.getProxy();
                    }
                }
                else {
                    return bean;
                }
            }

        };
    }
}

mockrestserviceserver配置在这里定义。

@Configuration
@Profile("test")
public class MockRestServiceServerConfiguration {

    @Bean
    public MockRestServiceServer mockRestServiceServer(RestTemplate restTemplate) {
        MockRestServiceServerBuilder builder = MockRestServiceServer.bindTo(restTemplate);
        MockRestServiceServer server = builder.bufferContent().build();
        return server;
    }
}

我看到的错误如下。

java.lang.AssertionError: Further request(s) expected leaving 1 unsatisfied expectation(s).
0 request(s) executed.
    at org.springframework.test.web.client.AbstractRequestExpectationManager.verify(AbstractRequestExpectationManager.java:159)
    at org.springframework.test.web.client.MockRestServiceServer.verify(MockRestServiceServer.java:116)

更新

我一直在调试,当然测试是在线程[main]上运行的,而jms侦听器是在线程[defaultmessagelistenercontainer-1]上运行的,所以我的问题变成了,当mock/verification需要由不同的线程使用时,我们应该如何处理mockito mocking?

ttisahbt

ttisahbt1#

结果发现 MockRestServiceServer 需要在闩锁等待后进行验证,如下面的代码所示。

Assert.assertTrue(JmsListenerWrapperConfiguration.latch.await(5, TimeUnit.SECONDS));
mockRestServiceServer.verify();

相关问题