![](/img/trans.png)
[英]Spring Boot Application is throwing exception when runs from Junit 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.