Spring boot 和 Flyway:集成测试前清除数据库数据

Spring boot and Flyway: Clear database data before integration tests

我正在使用 Spring 引导框架 (v2.0.2) 构建 REST 服务,我在其中对数据库进行了集成测试 运行。我在谷歌上搜索了很多,有大量关于在测试前清理数据库的文章,但不幸的是,我发现它们要么效率低下,要么是黑客攻击,而不是 Spring 引导。能否请您耐心等待并提出解决此问题的好方法?

理想情况下,我认为数据库不应该在每次测试之前清除,而是在某些组之前清除,比如套件或者可能是每个测试 class。找到的建议之一如下所示:

@Autowired
protected Flyway flyway;

@Before
public void init() {
    flyway.clean();
    flyway.migrate();
}

在每次测试之前重建数据库,显然效率不高。将其更改为静态上下文并使用 @BeforeClass 不起作用,因为 Spring 不会注入静态字段。

是否有一些好的方法可以从静态上下文访问此 flyway bean,以使此解决方案有效?

这里的子问题:Flyway有一个命令clean,它不仅清除数据,而且丢弃所有东西,然后migrate命令再次执行迁移。这似乎也是开销。由于无论如何都会在启动时检查迁移,所以我认为没有必要在每个测试组之前拆除和重建所有内容。只需清除数据就足够了。您能否就如何实现这一目标提供一些建议?

总而言之,我正在寻找一种在每组集成测试(例如每个 class)之前删除数据库数据(如果可能的话不删除表)的标准方法。我想每个人在使用 Spring 启动时都会面临这个任务,所以也许框架本身考虑了一些不错的解决方案。

谢谢!

您可以为您的测试创建配置文件。它会在所有测试之前 运行 一次。

@Configuration
public class TestConfig {
@Bean
public FlywayMigrationStrategy clean() {
    return flyway -> {
        flyway.clean();
        flyway.migrate();
    };
}
}

这个答案很有用,但它并没有让我一路走下去,所以我想我会回来添加一个答案,以防其他人正在寻求解决同样的问题。上面的 bean 定义很棒。

有 spring 个配置文件,其中有 5 种左右的可能性。我查看了文档以及人们如何使用它们,但走了另一条路。 Maven 有 6 个作用域,但在这种情况下有用的是 运行time 和 test。

当我深入研究 spring 配置文件以及在它们之间切换的各种方式时,我的情况似乎有点太复杂了。我只希望我的测试数据库被创建、结构化并填充一些数据,这样我就可以在我的 jpa spring 启动应用程序中测试存储库。我不想花 4 个小时来设置配置文件。并不是说从长远来看这不值得努力 运行,只是我想让事情发生变化。

当我执行 spring-boot:运行 时,我希望迁移非测试数据库,但我不希望其中有任何用于测试的 crud 数据。

因此,在实时应用程序中我想要一个几乎空的数据库,在测试期间,我希望 flyway 清理数据库,运行 版本化迁移并用测试数据填充它。

上面的答案让我找到了一个解决方案,当我的项目接近生产时,我可能会将其折叠到 spring 个配置文件中。

事实证明,spring-boot-test 提供了一个 @TestConfiguration 注释,您可以将其附加到 src/test/ 层次结构中的任何 class。我创建了一个 FlywayConfiguration class,其中包含上面提供的 bean 定义:

package com.foo.fooservice;

import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;

@TestConfiguration
public class FlywayMigrationConfig {

@Bean
public static FlywayMigrationStrategy cleanMigrateStrategy(){

        return flyway -> {
                flyway.clean();
                flyway.migrate();
                };
        }
}

所以现在,如果我想在测试中使用它,我会在适当的测试中添加另一个漂亮的注释 class- @Includes,@TestConfiguration 注释的伴侣 - 这样我就可以使用它配置方式与我可能使用 @BeforeClass 的方式相同:

@DataJpaTest
@Import(FlywayMigrationConfig.class) 
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class AccountUserRepoTest {



    @Autowired 
    private AccountUserRepo accountUserRepo;

    @Autowired
    private FlywayMigrationStrategy strategy;

这让我可以在每个测试 class 的基础上注入这个 flyway 迁移策略。 Spring 不会将您的 bean 自动注入每个测试 class,您现在只需将 @Includes 注释添加到适当的测试 class 即可使用此配置。您不必在要使用它的每个测试 class 中定义 bean。只需使用 @Includes(your@TestCongiguration-annoted-class).

我碰巧使用的是 postgresSQL 而不是 H2,因为我认为如果我正在对存储库实体进行集成测试,那么我也可以针对我将在生产中使用的内容进行测试。

此外:src/main/resources 将 jdbc 和飞路属性设置为开发架构名称,并且 jdbc url.

src/test/resources/application.properties 将架构名称设置为 'test'(您可以随意命名)。

您可能不想要的这种方法的一个缺点是粒度 - 为您以这种方式配置的每个测试 class 清理并重新填充数据库。

我个人喜欢这个,因为对于我正在测试的每个存储库 class 我希望刷新数据。如果我正在处理特定测试 class,我也喜欢这样,具有这种粒度级别的配置意味着 'run test' 开箱即用。 IDE 中无需特殊配置即可运行。