JUnit 5:将 spring 组件注入扩展(BeforeAllCallback / AfterAllCallback)

JUnit 5: Inject spring components to Extension (BeforeAllCallback / AfterAllCallback)

tl;dr:如何在所有测试之前将自定义数据提供程序实例化为 Spring 组件 运行?

是否有一种聪明的方法可以将 Spring 组件注入到实现 BeforeAllCallback 的自定义 JUnit Jupiter 扩展中? beforeAll 方法应该在 MyTestClass@ExtendWith(OncePerTestRunExtension.class) 执行之前触发一个复杂的过程。

我创建了一个 Spring 引导应用程序 (src/main/java),它为我的测试 (src/test/java) 提供了必要的数据。为测试准备数据最多可能需要几个小时。它还让我可以抽象地访问一些休息端点。

数据在所有测试classes 的过程中没有变化。所以我只想拉一次数据。

将所有测试写在一个 class 中是可行的,但我认为分成不同的 class 可以提供更好的概览。

在自定义 BeforeAllCallbackbeforeAll(ExtensionContext) 方法中,您可以通过 SpringExtension.getApplicationContext(extensionContext) 访问当前测试 class 的 Spring ApplicationContext ].

如果您将自定义数据提供程序配置为 ApplicationContext 中的 Spring 组件,则您可以从扩展中的 ApplicationContext 中检索该组件——例如,通过applicationContext.getBean(MyDataProvider.class).

如果您需要在测试之间处理数据并存储处理后的数据,您可以将其存储在 JUnit Jupiter 的 root ExtensionContext.Store 中。有关详细信息,请参阅 ExtensionContext.getRoot()ExtensionContext.Store 中的 getOrComputeIfAbsent(...) 变体。

下面是我如何使用 dataSource Spring bean 在我的数据库中设置一些测试数据,结合上面 Sam 的回答和这个回答:

import javax.sql.DataSource;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;

public class TestDataSetup implements BeforeAllCallback, ExtensionContext.Store.CloseableResource {

  private static boolean started = false;

  private DataSource dataSource;

  @Override
  public void beforeAll(ExtensionContext extensionContext) {
    synchronized (TestDataSetup.class) {
      if (!started) {
        started = true;

        // get the dataSource bean from the spring context
        ApplicationContext springContext = SpringExtension.getApplicationContext(extensionContext);
        this.dataSource = springContext.getBean(DataSource.class);

        // TODO: put your one-time db initialization code here

        // register a callback hook for when the root test context is shut down
        extensionContext
            .getRoot()
            .getStore(ExtensionContext.Namespace.GLOBAL)
            .put("TestDataSetup-started", this);
      }
    }
  }

  @Override
  public void close() {
    synchronized (TestDataSetup.class) {
      // TODO: put your db cleanup code here
    }
  }

(我不是 100% 确定线程安全,所以我添加了 synchronized 块只是为了安全。)

要启用此扩展,您只需将此注释添加到需要它的测试 类:

@ExtendWith(TestDataSetup.class)

好消息是 Junit 5 允许多个扩展,所以即使您的测试已经用 @ExtendWith(SpringExtension.class).

注释了,这仍然有效