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 可以提供更好的概览。
在自定义 BeforeAllCallback
的 beforeAll(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)
.
注释了,这仍然有效
tl;dr:如何在所有测试之前将自定义数据提供程序实例化为 Spring 组件 运行?
是否有一种聪明的方法可以将 Spring 组件注入到实现 BeforeAllCallback
的自定义 JUnit Jupiter 扩展中? beforeAll
方法应该在 MyTestClass
与 @ExtendWith(OncePerTestRunExtension.class)
执行之前触发一个复杂的过程。
我创建了一个 Spring 引导应用程序 (src/main/java
),它为我的测试 (src/test/java
) 提供了必要的数据。为测试准备数据最多可能需要几个小时。它还让我可以抽象地访问一些休息端点。
数据在所有测试classes 的过程中没有变化。所以我只想拉一次数据。
将所有测试写在一个 class 中是可行的,但我认为分成不同的 class 可以提供更好的概览。
在自定义 BeforeAllCallback
的 beforeAll(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)
.