我有一个带有AWS集成的简单spring引导应用程序。在集成测试中,我试图窥探带有@SqsListener注释的方法,并得到了有时没有监视bean的行为。
您可以在这里查看示例项目:https://github.com/Sanych/aws-sqs-spybean-troubleshooting
运行mvn clean verify
在本日志中,人们可能会注意到,3种测试方法中有2种是成功地被发现的:
2020-09-06 15:39:23.597 INFO 18372 --- [ main] com.aws.test.demo.SQSListenerIT : Started SQSListenerIT in 0.813 seconds (JVM running for 24.024)
2020-09-06 15:39:23.604 WARN 18372 --- [ main] com.aws.test.demo.SQSListenerIT : calling class com.aws.test.demo.SQSListener$MockitoMock$1506819983
2020-09-06 15:39:23.604 WARN 18372 --- [ main] com.aws.test.demo.SQSListenerIT : sendMessage to queue: test 1
2020-09-06 15:39:23.810 WARN 18372 --- [enerContainer-2] com.aws.test.demo.SQSListener : id: class com.aws.test.demo.SQSListener$MockitoMock$1506819983, received: 'test 1'
2020-09-06 15:39:23.929 WARN 18372 --- [ main] com.aws.test.demo.SQSListenerIT : calling class com.aws.test.demo.SQSListener$MockitoMock$1506819983
2020-09-06 15:39:23.929 WARN 18372 --- [ main] com.aws.test.demo.SQSListenerIT : sendMessage to queue: test 2
2020-09-06 15:39:24.052 WARN 18372 --- [enerContainer-2] com.aws.test.demo.SQSListener : id: class com.aws.test.demo.SQSListener, received: 'test 2'
2020-09-06 15:39:29.148 WARN 18372 --- [ main] com.aws.test.demo.SQSListenerIT : calling class com.aws.test.demo.SQSListener$MockitoMock$1506819983
2020-09-06 15:39:29.148 WARN 18372 --- [ main] com.aws.test.demo.SQSListenerIT : sendMessage to queue: test 3
2020-09-06 15:39:29.175 WARN 18372 --- [enerContainer-2] com.aws.test.demo.SQSListener : id: class com.aws.test.demo.SQSListener$MockitoMock$1506819983, received: 'test 3'
[ERROR] Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 6.468 s <<< FAILURE! - in com.aws.test.demo.SQSListenerIT
[ERROR] test2 Time elapsed: 5.218 s <<< ERROR!
org.awaitility.core.ConditionTimeoutException:
Assertion condition defined as a lambda expression in com.aws.test.demo.SQSListenerIT
Wanted but not invoked:
SQSListener.listen(<any string>);
-> at com.aws.test.demo.SQSListenerIT.lambda$sendMessageFromFileAndWaitForListenerToRead$0(SQSListenerIT.java:57)
Actually, there were zero interactions with this mock.
within 5 seconds.
at com.aws.test.demo.SQSListenerIT.sendMessageFromFileAndWaitForListenerToRead(SQSListenerIT.java:57)
at com.aws.test.demo.SQSListenerIT.test2(SQSListenerIT.java:42)
Caused by: org.mockito.exceptions.verification.WantedButNotInvoked:
Wanted but not invoked:
SQSListener.listen(<any string>);
-> at com.aws.test.demo.SQSListenerIT.lambda$sendMessageFromFileAndWaitForListenerToRead$0(SQSListenerIT.java:57)
Actually, there were zero interactions with this mock.
at com.aws.test.demo.SQSListenerIT.lambda$sendMessageFromFileAndWaitForListenerToRead$0(SQSListenerIT.java:57)我是不是遗漏了什么?
发布于 2022-02-03 15:08:20
也遇到了同样的问题。
来自SpyBean文档:
相同类型上下文中的所有bean都将与间谍一起包装。
在深入调查之后,对我来说唯一合理的解释是,SqsListener方法/ bean在 MockitoPostProcessor实际上用间谍代理包装现有Bean之前已经注册了MockitoPostProcessor。
因此,“真正的”bean实际上将被调用,但是这个调用不能用verify(...)来验证,因为调用不是通过Spy代理触发的。
最好知道:@SqsListener方法是通过QueueMessageHandler注册的,QueueMessageHandler是由SqsAutoConfiguration构造的。因此,如果SqsAutoConfiguration在MockitoPostProcessor包装间谍bean之前运行,则调用不会通过间谍代理。
可能的解决方案
我用下面的方法来解决这个问题。
public class MyService {
@Autowired
private OtherService otherService;
@SqsListener("queue")
public void listen(@NotificationMessage Event event) {
oterService.doWork();
}
}MyService )与集成测试(实际上调用MyService#listen的仅测试)分离为集成测试(@SpringBootTest)中的@SpyBean侦听器bean本身,而是侦听器使用的bean。(我的example)verify(otherService, timeout(500)).doWork()中的OtherService)
虽然这个答案相当抽象,但我希望这会有任何帮助。
编辑:仅仅使用OtherService来嘲笑MockBean是不够的。我必须显式地创建一个OtherService模拟(mock(OtherService.class),并使用包私有setter在我的MyService中设置它。我承认,这不是最干净的解决方案,但到目前为止,这是唯一对我有效的解决方案。
编辑(2022-02-16):从SpringCloudAWS2.4开始,就有一个@SqsTest注释可用于此目的:https://github.com/awspring/spring-cloud-aws/releases/tag/v2.4.0 https://github.com/awspring/spring-cloud-aws/blob/v2.4.0/spring-cloud-aws-samples/spring-cloud-aws-sqs-sample/src/test/java/io/awspring/cloud/sqs/sample/SqsSampleApplicationTests.java
https://stackoverflow.com/questions/63764720
复制相似问题