Java @在应用程序上下文启动时运行的BeforeAll JUnit/spring启动测试替代方案

Java @在应用程序上下文启动时运行的BeforeAll JUnit/spring启动测试替代方案,java,spring,junit,spring-test,Java,Spring,Junit,Spring Test,我正在编写一个利用嵌入式数据库的@Repository/@Service集成测试。在我的测试类中,我想用一些数据预加载我的数据库 我目前正在使用@beforeach加载示例数据,但是,此代码在我的类中的每个测试中都会运行 在加载Spring应用程序上下文之后,但在运行任何测试之前,是否有任何方法可以加载测试数据 我目前的做法是: @BeforeEach public void before() { repository.save(...); // -> prepopulates r

我正在编写一个利用嵌入式数据库的
@Repository/@Service
集成测试。在我的测试类中,我想用一些数据预加载我的数据库

我目前正在使用
@beforeach
加载示例数据,但是,此代码在我的类中的每个测试中都会运行

在加载Spring应用程序上下文之后,但在运行任何测试之前,是否有任何方法可以加载测试数据

我目前的做法是:

@BeforeEach
public void before() {
    repository.save(...); // -> prepopulates repository with sample data
}

@Test
public void testService() {
    service.get(...); // -> gathers existing record
}

@Test
public void deleteById() {
    service.delete(...); // -> deletes existing record
}
然而。。。有了这个,我需要在每次测试后清除记录。否则,很容易违反任何唯一的约束


而不是在每次测试之前使用要求运行的
@beforeach
。。。是否有可能在加载spring应用程序上下文之后,以一种之前的方式加载它?

在这种情况下,我只需要为测试类创建一个构造函数。它将在一切发生之前被触发

@beforeach在每次测试之前运行,但在所有初始化之后运行


您也可以只使用Mockito和mock结果,而无需清理和过度复杂

在这种情况下,我将为测试类创建一个构造函数。它将在一切发生之前被触发

@beforeach在每次测试之前运行,但在所有初始化之后运行


您也可以只使用Mockito并模拟结果,而无需清理和过度复杂

只需将以下代码片段添加到代码中即可。这就像检测
Spring
应用程序是否真正启动一样

@Configuration
public class AppConfig implements ApplicationListener<ApplicationReadyEvent> {

    /**
     * This is to indicate in the logs when the application has actually started and everything is loaded.
     */
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        ApplicationContext context = event.getApplicationContext();
        Environment env = context.getEnvironment();
        // do what you want on application start
    }
}
@配置
公共类AppConfig实现ApplicationListener{
/**
*这是为了在日志中指示应用程序实际启动和加载所有内容的时间。
*/
@凌驾
ApplicationEvent上的公共无效(ApplicationReadyEvent事件){
ApplicationContext context=event.getApplicationContext();
Environment env=context.getEnvironment();
//在应用程序启动时执行所需操作
}
}

p.S.对于test
@Sql
中的数据库操作,正如评论中所提到的,是最好的选择。

只需在代码中添加以下代码片段即可。这就像检测
Spring
应用程序是否真正启动一样

@Configuration
public class AppConfig implements ApplicationListener<ApplicationReadyEvent> {

    /**
     * This is to indicate in the logs when the application has actually started and everything is loaded.
     */
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        ApplicationContext context = event.getApplicationContext();
        Environment env = context.getEnvironment();
        // do what you want on application start
    }
}
@配置
公共类AppConfig实现ApplicationListener{
/**
*这是为了在日志中指示应用程序实际启动和加载所有内容的时间。
*/
@凌驾
ApplicationEvent上的公共无效(ApplicationReadyEvent事件){
ApplicationContext context=event.getApplicationContext();
Environment env=context.getEnvironment();
//在应用程序启动时执行所需操作
}
}
p.S.对于test
@Sql
中的数据库操作,如评论中所述,是最好的选择

在Spring应用程序上下文加载之后,有什么方法可以加载测试数据吗

基本上是的,我认为你可以做到:

其思想是在应用程序上下文启动时或启动过程中加载SQL数据

例如,spring boot与Flyway的集成就是这样工作的(Flyway的bean被创建和加载)。因此,从理论上讲,您只需将Flyway与测试迁移一起使用,测试迁移将包含生成测试数据的所有相关SQL脚本

技术上你怎么能做到这一点

这里有一个方法:

创建一个特殊的bean(就像它与Flyway的工作方式一样),该bean取决于您的存储库,并在构建后保存数据:

@Component
public class SqlGenerationBean {

   @Autowired
   private MyRepository repo;

   @PostConstruct
   public void init() {
      repo.save();
   } 
}
另一种方法是创建一个侦听器,在应用程序上下文启动时调用该侦听器,然后再次调用相同的
repo.save()

在这两种情况下,bean/listener代码都不应该从生产环境中访问(它仅用于测试):因此将其放在
src/test/java

现在,一旦应用程序上下文启动,您就可以使用一个巧妙的技巧:

使用
@Transactional
注释标记测试。Spring将把代码包装在一个人工事务中,该事务将自动回滚(即使测试成功),这样,您将在测试期间修改的所有数据都将回滚,并且基本上在每次测试之前,您将具有相同的状态(即与应用程序上下文启动时/之后的数据库状态相同)。当然,如果在测试中使用DDL,有些数据库不能将其作为事务的一部分,但它实际上取决于数据库

这里另一个有趣的地方是,应用程序上下文甚至可以在测试用例之间缓存(只创建一次),所以请记住这一点

在Spring应用程序上下文加载之后,有什么方法可以加载测试数据吗

基本上是的,我认为你可以做到:

其思想是在应用程序上下文启动时或启动过程中加载SQL数据

例如,spring boot与Flyway的集成就是这样工作的(Flyway的bean被创建和加载)。因此,从理论上讲,您只需将Flyway与测试迁移一起使用,测试迁移将包含生成测试数据的所有相关SQL脚本

技术上你怎么能做到这一点

这里有一个方法:

创建一个特殊的bean(就像它与Flyway的工作方式一样),该bean取决于您的存储库,并在构建后保存数据:

@Component
public class SqlGenerationBean {

   @Autowired
   private MyRepository repo;

   @PostConstruct
   public void init() {
      repo.save();
   } 
}
另一种方法是创建一个侦听器,在应用程序上下文启动时调用该侦听器,然后再次调用相同的
repo.save()

在这两种情况下,bean/listener代码都不应该从生产环境中访问(它仅用于测试):因此将其放在
src/test/java

现在,一旦应用程序上下文启动,您就可以使用一个巧妙的技巧:

@Tra标记您的测试