JUnit 5:将弹簧组件注入扩展(在AllCallback之前/在AllCallback之后)

2022-09-03 09:47:57

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

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

我创建了一个Spring Boot应用程序(),它为我的测试()提供了必要的数据。数据可能需要几个小时才能准备好进行测试。它还使我能够抽象地访问一些休息终结点。src/main/javasrc/test/java

数据不会在所有测试类的进程之间更改。所以我只想拉一次数据。

在一个类中编写所有测试是可行的,但我认为将分离到不同的类中可以更好地概述。


答案 1

在自定义的方法中,您可以通过 访问当前测试类的Spring。beforeAll(ExtensionContext)BeforeAllCallbackApplicationContextSpringExtension.getApplicationContext(extensionContext)

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

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


答案 2

以下是我如何实现它,通过使用Spring bean在我的数据库中设置一些测试数据,通过将上面的Sam的答案与此答案相结合:https://stackoverflow.com/a/51556718/278800dataSource

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)


推荐