如何避免使用 @Scheduled 或缓存测试上下文中的 JMS/Kafka 侦听器的 Spring bean 处于活动状态?

问题描述 投票:0回答:1

在使用

@SpringBootTest
执行周期任务或具有 JMS 或 Kafka 侦听器的应用程序中使用
@Scheduled
编写集成测试时,可能会发生以下情况:

  1. 测试 1 开始。创建应用程序上下文并将其添加到测试上下文缓存中。
  2. 测试 1 结束。应用程序上下文及其所有 bean 在测试上下文缓存中保持“活动”状态。
  3. 测试 2 开始。因为在两个测试中启动的 bean 之间存在细微的差异(我知道我们应该尽量减少这种差异,以便从上下文缓存中受益,但有时是不可避免的),因此会创建一个新的应用程序上下文并将其添加到测试上下文缓存中。

当测试 2 运行时,

@Scheduled
beans 或任何侦听器仍然处于“活动”状态。因此,并非来自“当前”应用程序上下文的侦听器可能会拾取消息或执行计划任务。这可能会导致测试不稳定。

同样,测试可能已经结束,而某些异步行为仍会在后台继续。

人们用什么来避免这种情况?

我正在考虑向此类名为

TestSuspendable
的 bean 添加一个接口,其中包含
suspend()
resume()
方法,通过 JUnit 5 扩展将在每次测试结束时挂起此类 bean,并在每次测试开始时恢复它们。但我不喜欢仅仅为了这样的测试而需要更改生产代码。所以我想听听是否有更好的选择。

java spring spring-boot spring-test
1个回答
0
投票

涉及的bean(监听器容器和调度程序等)通常都实现了Spring的

Lifecycle
接口。因此,作为一个快速技巧,您可以为
BeforeAllCallback
AfterAllCcallback
分别为
start
stop
这些 bean 创建一个 JUnit5 侦听器。这应该会停止任务的监听和调度。

public class LifecycleExtension implements BeforeAllCallback, AfterAllCallback {

  void beforeAll(ExtensionContext context) throws Exception {
    var ctx = SpringExtension.getApplicationContext(context);
    Map<String, Lifecycle> beans = ctx.getBeansOfType(Lifecycle.class);
    for (var bean = beans.values()) {
      if (!bean.isRunning()) {
        bean.start();
      }
    }
  }

  void afterAll(ExtensionContext context) throws Exception {
    var ctx = SpringExtension.getApplicationContext(context);
    Map<String, Lifecycle> beans = ctx.getBeansOfType(Lifecycle.class);
    for (var bean = beans.values()) {
      if (bean.isRunning()) {
        bean.stop();
      }
    }
  }
}

沿着这些思路做一些事情可能会奏效。还没有测试过,只是从我的头顶输入它。但它可能为您提供了足够的信息来继续。

© www.soinside.com 2019 - 2024. All rights reserved.