繁体   English   中英

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

[英]@BeforeAll JUnit/spring-boot-test alternative that runs when application context starts

我正在编写一个利用嵌入式数据库的@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需要在每次测试之前运行......是否可以在加载 spring 应用程序上下文之后以@BeforeAll类型的方式加载它?

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

PS对于测试中的数据库操作, @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/侦听器代码不应该从生产中访问(它仅用于测试):因此将它放在src/test/java下的某个位置,例如

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

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

这里另一个有趣的点是,即使在测试用例之间(仅创建一次),应用程序上下文也可以缓存,因此请记住这一点。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM