简体   繁体   English

为什么我的 MockBeans 和 MockRestServiceServer 在 Spring Boot 中测试 JMS 侦听器时没有返回正确的响应

[英]Why are my MockBeans and MockRestServiceServer not returning proper responses when testing JMS Listener in Spring Boot

I am having an issue when trying to integration test my JMS listener with Mockito and MockRestServiceServer .我在尝试使用MockitoMockRestServiceServer集成测试我的 JMS 侦听器时遇到问题。 Even if I'm using the correct Mockito.when annotations, they are coming up as null , and the MockRestServiceServer is acting as if it isn't being called.即使我使用了正确的Mockito.when注释,它们也会以null的形式出现,并且MockRestServiceServer的行为就像没有被调用一样。 If I switch instead to test against the myService component that the jms listener calls, the mocks and the MockRestServiceServer calls are working as expected, which is puzzling.如果我改为针对 jms 侦听器调用的myService组件进行测试,则模拟和MockRestServiceServer调用按预期工作,这令人费解。 I am connecting to an embedded ActiveMQ broker for the test and I am using Spring Boot 2.2.8.RELEASE and JDK 8.x if that helps.我正在连接到嵌入式 ActiveMQ 代理进行测试,如果有帮助,我正在使用 Spring Boot 2.2.8.RELEASE 和 JDK 8.x。

Here is the JMS Listener Class这是 JMS 监听器 Class

@Component
public class MyJmsListener {

    @Autowired
    private MyService myService;

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

Here is the JMS Listener Test Class这是 JMS 侦听器测试 Class

@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));
    }
...
}

I have a JmsListenerWrapperConfiguration that will allow me to wrap the countdown latch into the jms listener.我有一个 JmsListenerWrapperConfiguration,它允许我将倒计时锁存器包装到 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;
                }
            }

        };
    }
}

The MockRestServiceServer configuration is defined here. 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;
    }
}

The error that I see is as follows.我看到的错误如下。

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)

Update更新

I've been debugging and of course the test is running on thread[main], whereas the JMS listener is running on thread[DefaultMessageListenerContainer-1], so my question then becomes, what should we do with Mockito mocking when the mocks/verifications need to be used by separate threads?我一直在调试,当然测试在线程 [main] 上运行,而 JMS 侦听器在线程 [DefaultMessageListenerContainer-1] 上运行,所以我的问题是,当模拟/验证时,我们应该如何处理 Mockito mocking需要由单独的线程使用?

It turns out that the MockRestServiceServer needed to verify after the latch is awaiting as shown in this code below.事实证明, MockRestServiceServer需要在闩锁等待后进行验证,如下面的代码所示。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Boot @Async批注和MockRestServiceServer - Spring Boot @Async annotation and MockRestServiceServer Spring 启动、jms 监听和数据库事务 - Spring boot, jms listener and database transaction 运行多个 Spring Boot 测试时,@MockBean 在 JMS 侦听器中使用不同的实例 - @MockBean uses different instance in JMS listener when running multiple Spring Boot tests 春季启动:MockMvc返回奇怪的响应 - Spring Boot: MockMvc returning strange responses 使用Spring JMS时未调用侦听器方法 - Listener method not called when using Spring JMS Spring-Boot-Test @MockBeans是否应该符合@ConditionalOnBean条件? - Are Spring-Boot-Test @MockBeans supposed to qualify for @ConditionalOnBean conditions? Spring Boot @MockBeans - 如何在多个测试类中使用相同的 bean - Spring Boot @MockBeans - How to use the same beans in multiple test classes 使用多部分请求测试 MockRestServiceServer spring-test - Testing MockRestServiceServer spring-test with multipart request 如何使用Spring的MockRestServiceServer模拟相同请求的多个响应? - How to mock multiple responses for same request using spring's MockRestServiceServer? 为什么 Hibernate 从 @Transactional 方法(Spring boot)返回对象时不能完全解析我的对象? - Why doesn't Hibernate fully resolve my object when returning it from a @Transactional method (Spring boot)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM