java - 如何在 Spring 中真正单独运行每个集成测试,或者至少在每个测试之前运行所有命令行运行程序?

标签 java spring spring-boot spring-test

我有一个 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/

相关文章:

java - 无法推断 ResponseEntity<> 的类型参数

java - Android中如何获取方法名称?

spring - 如何将spring boot项目转换为spring mvc

angular - 使用 Spring Boot 和 Angular 2 CLI 进行 Google OAuth2 身份验证

mysql - Hibernate 多对多延迟初始化异常

java - 如何正确合并文档?

java - 什么是 transient 和 volatile 修饰符?

java - 如何在按下 ImageView 时立即启动音频?

java - 字符串 * 的 UTF8 表示对于常量池来说太长

java - 如何组合两个异步 Web 客户端调用,假设一个调用遇到一些异常