[英]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
.我在尝试使用
Mockito
和MockRestServiceServer
集成测试我的 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)
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.