在应用程序上下文启动时运行的@BeforeAll JUnit / spring-boot-test替代方案

问题描述

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

我当前正在使用@BeforeEach加载示例数据,但是,该代码在班级中的每个测试上运行。

在加载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
}

但是...与此相关,我必须在每次测试后清除记录。否则,很容易违反任何唯一约束。

不是使用在每次测试之前都需要运行的@BeforeEach……是否可以以@BeforeAll这种方式加载,该方式在加载Spring应用程序上下文之后发生?

解决方法

只需将以下代码段添加到您的代码中即可。就像您可以检测到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
    }
}

P.S。。对于测试中的数据库操作,@Sql是评论中提到的最佳人选。

,

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

基本上可以,我认为您可以做到:

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

例如,Spring Boot与Flyway集成以这种方式工作(创建并加载Flyway的bean)。因此,从理论上讲,您只能在测试迁移中使用Flyway,该迁移将包含测试数据生成的所有相关SQL脚本。

您如何从技术上做到这一点?

这是一种方法:

创建一个依赖于您的存储库的特殊bean(就像它与Flyway一样),并在后期构造中保存数据:

@Component
public class SqlGenerationBean {

   @Autowired
   private MyRepository repo;

   @PostConstruct
   public void init() {
      repo.save();
   } 
}

另一种方法是创建一个侦听器,该侦听器将在应用程序上下文启动时被调用,然后再次调用相同的repo.save()

在两种情况下,都不能从生产环境访问Bean / Listener代码(仅用于测试):例如,将其放在src/test/java

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

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

另一个有趣的地方是,即使在测试用例之间(仅创建一次),都可以缓存应用程序上下文。

,

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

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

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...