我有一个 Spring Boot 应用程序,并且正在使用 spring-boot-starter-test。
我有一堆集成测试,它们使用 REST 调用将数据插入到应用程序中。我使用 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
每次测试后,我都会在数据库中得到一些数据。我希望每个测试都是真正独立的,但我还没有找到做到这一点的方法。我尝试在每个测试中添加 @Rollback,但由于我是通过 REST 调用从外部插入数据,所以这是行不通的。
因此,之前我采取了一种相当低级的方式,通过执行删除查询来删除测试之间的所有数据(即类似 Query deleteProjects =entityManager.createQuery("DELETE FROM Project"); deleteProjects运行测试后为每个实体执行 .executeUpdate();
)。
但是,我最近添加了一个将在 CommandLineRunner 中创建的管理员用户帐户。我发现这个 CommandLineRunner 对于所有组合测试也只运行一次,所以在第一个测试完成并且所有数据被删除后,我失去了我的管理员角色。
设置此功能的好方法是什么?我意识到启动整个应用程序需要一些时间,因此全新的启动并不理想。在每次测试之前告诉 Spring 运行 CommandLineRunner 的某种方法会很好。我不想自己实例化并运行它,这会很麻烦,而且我不确定这在事务方面如何工作。我可以在查询中排除此管理员用户帐户被删除,但我仍然在系统周围进行黑客攻击。
最佳答案
目前,您遇到了先有鸡还是先有蛋的问题,需要存在此管理员帐户并且该管理员帐户存在 Spring 上下文。我发现一个好方法是拥有一个 Spring Profile @Profile("test")
并将其放在某个 Component
上,该组件创建您需要的管理员帐户:
@Component
@Profile("test")
public class CreateAdminBean {
@Autowired
UserRepo repo;
public CreateAdminBean() {
// TODO your job but something like:
User admin = new User();
admin.setAdmin(true);
repo.create(admin);
}
}
如果您希望测试真正彼此独立,您将需要每次都重新创建上下文并确保每次都删除数据库。这将花费你大量的时间,而且在我看来是不必要的,但如果你有你的理由,你就有你的理由。我个人会 mock 所有的服务。
您可以只使用数据库 JPA Hibernate,就像 spring.jpa.hibernate.ddl-auto= create-drop
一样。我通常不会这样做,只是有一个方法可以清除所有表并在每次测试后运行该方法,但这不是您在问题中所要求的,我希望看到一个 @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
在您的测试代码中。
关于java - 如何在 Spring 中真正单独运行每个集成测试,或者至少在每个测试之前运行所有命令行运行程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49999633/