java - 运行多个 Spring Boot 测试时,@MockBean 在 JMS 监听器中使用不同的实例

标签 java spring unit-testing jms

我编写了一个 Spring Boot 测试,该测试写入 JMS 队列并期望通过 JMS 监听器进行一些处理。在监听器中,我尝试从 S3 读取一个对象。 AmazonS3 类应替换为 MockBean。在我的测试中,我像这样设置了模拟:

@SpringBootTest
public class MyTest {

    @Autowired
    MyJmsPublisher jmsPlublisher;
    @MockBean
    AmazonS3 amazonS3;

    @Test
    public void test() {
        final S3Object s3Object = mock(S3Object.class);
        when(s3Object.getObjectContent()).thenReturn(mock(S3ObjectInputStream.class));
        when(amazonS3.getObject(anyString(), anyString())).thenReturn(s3Object);
        
        jmsPlublisher.publishMessage("mymessage");
        Awaitility.await().untilAsserted(() -> {
            //wait for something here
        });
    }
}


@Component
@RequiredArgsConstructor
public class MyJmsPublisher {

    private final JmsTemplate jmsTemplate;

    public void publishMessage(String message) {
        jmsTemplate.convertAndSend("destination", message);
    }
}

@Component
@RequiredArgsConstructor
public class MyJmsListener {

    private final AmazonS3 amazonS3;

    @JmsListener(destination = "destination")
    public void onMessageReceived(String message) {
        final S3ObjectInputStream objectContent = amazonS3.getObject("a", "b").getObjectContent();
        // some logic here
    }
}

但问题是,当运行多个 Spring Boot 测试时,MyJmsListener 类包含一个与测试中创建的模拟不同的模拟。这是一个模拟,但例如 getObjectContent() 返回 null。 但是当我单独运行测试时,一切正常。

我尝试将 AmazonS3 bean 注入(inject) MyJmsPublisher 并在那里调用模拟方法,并且成功了。所以我怀疑,这是因为 JMS 监听器在不同的线程中运行。

我找到了this thread并将 reset 设置为所有可用选项,但没有任何区别。我还尝试了这个对他们有用的OP方法,我通过 @Bean 注释创建了一个模拟,如下所示:

@Configuration
public class MyConfig {
   @Bean
   @Primary
   public AmazonS3 amazonS3() {
      return Mockito.mock(AmazonS3.class);
   }
}

但这与上面提到的行为相同。

那么,当使用不同的线程(例如使用@JMSListener)时,您实际上可以使用@MockBean注释吗?或者我错过了什么?

最佳答案

带有@JmsListener注释方法的Spring Bean在被辅助线程激活时会注入(inject)从先前测试执行中泄漏的bean。实际的解决方法是将测试执行器配置为对每个类使用独立的虚拟机,以避免此问题。

对于 Maven 执行,您可以通过设置 reuseForks 选项来配置 maven-failsafe-pluginmaven-surefire-plugin。例如:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <configuration>
        <reuseForks>false</reuseForks>
    </configuration>
</plugin>

您还可以在 JUnit IDE 工具中轻松将Fork 模式更改为Class,以执行多个测试。 IntelliJ 示例:

IntelliJ JUnit Fork mode

使用@DirtiesContext不起作用,不幸的是,我仍然找不到这个问题的根本原因 - 我的预感是这可能与使用内存中的实例有关ActiveMQ 代理,位于执行共享的 VM 实例中。

关于java - 运行多个 Spring Boot 测试时,@MockBean 在 JMS 监听器中使用不同的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68080623/

相关文章:

java - Servlet 的 Spring root WebApplicationContext

spring - Spring 型材的替代品

unit-testing - 如何在不访问服务器的情况下在 XPage 页面中进行单元测试?

javascript - 使用 Sinon.js 测试 navigator.browserLanguage 或 navigator.language

java - 方法结束时对java返回的混淆

java - 装饰器模式和哈希码

jquery - 在spring中使用jquery表单发布到DB

java - 如何正确处理来自 ListenableFuture guava 的异常?

java - 为什么 ClassNotFoundException 会表现出这种行为?

java - 默认包的 JUnit 测试用例