首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring Boot - @SQSListener和@SpyBean没有合作吗?

Spring Boot - @SQSListener和@SpyBean没有合作吗?
EN

Stack Overflow用户
提问于 2020-09-06 13:32:23
回答 1查看 889关注 0票数 2

我有一个带有AWS集成的简单spring引导应用程序。在集成测试中,我试图窥探带有@SqsListener注释的方法,并得到了有时没有监视bean的行为。

您可以在这里查看示例项目:https://github.com/Sanych/aws-sqs-spybean-troubleshooting

运行mvn clean verify

在本日志中,人们可能会注意到,3种测试方法中有2种是成功地被发现的:

代码语言:javascript
复制
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)

我是不是遗漏了什么?

EN

回答 1

Stack Overflow用户

发布于 2022-02-03 15:08:20

也遇到了同样的问题。

来自SpyBean文档:

相同类型上下文中的所有bean都将与间谍一起包装。

在深入调查之后,对我来说唯一合理的解释是,SqsListener方法/ bean在 MockitoPostProcessor实际上用间谍代理包装现有Bean之前已经注册了MockitoPostProcessor

因此,“真正的”bean实际上将被调用,但是这个调用不能用verify(...)来验证,因为调用不是通过Spy代理触发的。

最好知道:@SqsListener方法是通过QueueMessageHandler注册的,QueueMessageHandler是由SqsAutoConfiguration构造的。因此,如果SqsAutoConfigurationMockitoPostProcessor包装间谍bean之前运行,则调用不会通过间谍代理。

可能的解决方案

我用下面的方法来解决这个问题。

代码语言:javascript
复制
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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63764720

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档