在测试类之外使用Spring Boot/JUnit 5连接到测试生命周期事件

在测试类之外使用Spring Boot/JUnit 5连接到测试生命周期事件,spring,spring-boot,junit,junit5,Spring,Spring Boot,Junit,Junit5,JUnit5具有类似于@beforeach,@BeforeAll,@aftereall,@AfterEach注释的特性,这些特性允许您在测试生命周期事件期间执行代码,例如清除测试之间共享的状态 我想为某些测试配置提供一种自动执行此操作的方法,而无需记住在每个测试中放置这些生命周期挂钩 例如: 如果我有一个加载一些存根数据源的Spring测试配置: 接口数据提供程序{ 字符串getData(字符串id); } 以及一个依赖于此的类: @组件 依赖于数据提供程序的类{ 私有最终数据提供者数据提供者

JUnit5具有类似于
@beforeach
@BeforeAll
@aftereall
@AfterEach
注释的特性,这些特性允许您在测试生命周期事件期间执行代码,例如清除测试之间共享的状态

我想为某些测试配置提供一种自动执行此操作的方法,而无需记住在每个测试中放置这些生命周期挂钩

例如:

如果我有一个加载一些存根数据源的Spring测试配置:

接口数据提供程序{
字符串getData(字符串id);
}
以及一个依赖于此的类:

@组件
依赖于数据提供程序的类{
私有最终数据提供者数据提供者;
@自动连线
依赖于DataProvider的类(DataProvider DataProvider){
this.dataProvider=dataProvider;
}
公共字符串进程(字符串id){
String data=dataProvider.get(id);
返回(数据)的一些处理;
}
}
正常情况下,这可能会影响后端,但对于我的测试,我将使用内存中的解决方案替换它:

@TestComponent
类InMemoryDataProvider实现数据提供程序{
私有映射数据=新HashMap();
公共void setData(字符串id、字符串数据){
data.put(id,data);
}
公共字符串getData(字符串id){
返回data.get(id);
}
公共空间清除(){
data.clear();
}
}
在我的测试中,我可能想使用它来删除后端中的数据,如:

@SpringBootTest
@导入({InMemoryDataProvider.class})
依赖于DataProviderTests的类{
@自动连线InMemoryDataProvider数据提供者;
@依赖于数据提供程序的自动连线类依赖于数据提供程序的自动连线类;
@试验
public void应该\u正确\u处理\u数据(){
//假设我有一个带值的id
setData(“存根id”、“存根值”);
//当我处理我的id时
var result=classthattdependsondataprovider.process(“存根id”);
//然后我收到了预期的结果
断言(result).isWhatIExpect();
}
//更多@测试
//我不想在每个测试类中都这样做
@之后
公共无效拆卸(){
dataProvider.clear();
}
} 
我希望能够删除这里的
tearDown()
方法,该方法在每次
之后都用
@AfterEach
注释,并将该行为移动到测试组件/test-fake中,或者移动到配置类中,以便使用一组这样的提供程序,维护一组测试很容易,这些测试将用假版本替换它们,而无需手动管理每个测试的生命周期

是否有某种Spring特性、生命周期事件或JUnit5特性允许这样做


请原谅这个简单的例子,很明显这对于一个如此简单的测试来说是过分的,但它只是一个讨论的参考。假设
@MockBean
或使用mocking libs不是一个选项。

您可以使用JUnit5扩展:

例如,您的扩展如下所示:

public class InMemoryDataProviderExtension implements AfterEachCallback {

    /**
     * {@inheritDoc}
     */
    @Override
    public void afterEach(final ExtensionContext context) throws Exception {
        final ApplicationContext applicationContext = SpringExtension.getApplicationContext(context);

        final InMemoryDataProvider inMemoryDataProvider = applicationContext.getBean(InMemoryDataProvider.class);
        inMemoryDataProvider.clear();

    }
}
请注意:

  • SpringExtension.getApplicationContext(上下文)获取spring应用程序上下文,因此您可以检索上下文中定义的bean
  • 扩展在每个回调接口之后实现,但对于其他扩展点(即BeforeAchCallback、BeforeAllCallback等)存在其他扩展
要在测试中激活扩展,请执行以下操作:

@SpringBootTest
@ExtendWith(InMemoryDataProviderExtension.class)
public class ClassThatDependsOnDataProviderTests { ... }

您可以使用JUnit5扩展:

例如,您的扩展如下所示:

public class InMemoryDataProviderExtension implements AfterEachCallback {

    /**
     * {@inheritDoc}
     */
    @Override
    public void afterEach(final ExtensionContext context) throws Exception {
        final ApplicationContext applicationContext = SpringExtension.getApplicationContext(context);

        final InMemoryDataProvider inMemoryDataProvider = applicationContext.getBean(InMemoryDataProvider.class);
        inMemoryDataProvider.clear();

    }
}
请注意:

  • SpringExtension.getApplicationContext(上下文)获取spring应用程序上下文,因此您可以检索上下文中定义的bean
  • 扩展在每个回调接口之后实现,但对于其他扩展点(即BeforeAchCallback、BeforeAllCallback等)存在其他扩展
要在测试中激活扩展,请执行以下操作:

@SpringBootTest
@ExtendWith(InMemoryDataProviderExtension.class)
public class ClassThatDependsOnDataProviderTests { ... }