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

Java Spring boot和Flyway:在集成测试之前清除数据库数据,java,spring-boot,junit,flyway,Java,Spring Boot,Junit,Flyway,我正在使用SpringBootFramework(v2.0.2)构建一个REST服务,在那里我在数据库上运行集成测试。我在谷歌上搜索了很多关于测试前清理数据库的文章,但不幸的是,我发现它们要么效率低下,要么是黑客攻击,不适合Spring boot。请你容忍我,提出解决这个问题的好办法好吗 理想情况下,我认为数据库不应该在每次测试之前清除,而应该在某组测试之前清除,比如套件或者每个测试类。找到的建议之一如下所示: @Autowired protected Flyway flyway; @Befo

我正在使用SpringBootFramework(v2.0.2)构建一个REST服务,在那里我在数据库上运行集成测试。我在谷歌上搜索了很多关于测试前清理数据库的文章,但不幸的是,我发现它们要么效率低下,要么是黑客攻击,不适合Spring boot。请你容忍我,提出解决这个问题的好办法好吗

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

@Autowired
protected Flyway flyway;

@Before
public void init() {
    flyway.clean();
    flyway.migrate();
}
在每次测试之前重建数据库,显然效率不高。将其更改为静态上下文并使用
@BeforeClass
不起作用,因为Spring不会注入静态字段

有什么好方法可以从静态上下文访问这个Flywaybean,从而使这个解决方案工作吗

这里的子问题:Flyway有一个clean命令,它不仅清除数据,而且删除所有内容,然后migrate命令再次执行迁移。这看起来也像是开销。由于迁移是在启动时检查的,所以我认为没有必要在每个测试组之前拆除并重建所有内容。仅仅清理数据就足够了。你能就如何实现这一目标提出一些建议吗

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


谢谢大家!

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

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

这个答案很有用,但它并没有让我一路走到那里,所以我想我会回来补充一个答案,以防其他人正在寻找解决这个问题的方法。上面的bean定义非常棒

有5种左右可能性的弹簧外形。我查看了文档以及人们如何使用它们,但走了另一条路。Maven有6个作用域,但在本例中有用的是runtime和test

当我深入研究spring概要文件以及在它们之间切换的各种方式时,我的情况似乎有点太复杂了。我只希望我的被测数据库被创建、检查并填充一些数据,这样我就可以在我的jpa spring启动应用程序中测试存储库。我不想花4个小时建立个人资料。并不是说从长远来看这不是一项值得努力的努力,只是我想让事情进展起来

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

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

上面的答案让我找到了一个解决方案,随着我的项目越来越接近生产,我可能会将其加入到spring概要文件中

原来SpringBootTest提供了一个注释,您可以将它附加到src/test/hierarchy中的任何类。我创建了一个FlywayConfiguration类,其中包含上面提供的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();
                };
        }
}
现在,如果我想在测试中使用它,我在适当的测试类中添加了另一个漂亮的注释-@Includes,它是@TestConfiguration注释的一个伴侣-,这样我就可以像使用@BeforeClass一样使用这个配置了:

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



    @Autowired 
    private AccountUserRepo accountUserRepo;

    @Autowired
    private FlywayMigrationStrategy strategy;
这允许我在每个测试类的基础上注入这种flyway迁移策略。Spring不会将您的bean自动注入到每个测试类中,您现在可以通过向适当的测试类添加@Includes注释来使用此配置。您不必在每个要使用bean的测试类中定义它。只需使用@Includes(your@TestCongiguration-注释类)

我碰巧使用的是postgresSQL而不是H2,因为我认为如果我在存储库实体上进行集成测试,我还可以根据我将在生产中使用的内容进行测试

另外:src/main/resources将jdbc和flyway属性设置为dev模式名和JDBCURL

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

这种方法的一个缺点是粒度,您可能不希望这样,即对于以这种方式配置的每个测试类,都会清理并重新填充数据库


我个人喜欢这样,因为对于我正在测试的每个存储库类,我都希望数据被刷新。如果我正在处理一个特定的测试类,我也喜欢这样,在这个粒度级别上进行配置意味着“运行测试”是开箱即用的。IDE中无需特殊配置即可工作。

为什么不在测试中使用
@Transactional
。这样,数据库总是干净的。为什么不使用简单的删除或截断表呢?您可以选择要删除的表?还可以修复顺序,以便处理外键约束。如果您想使用库,可以看看DBUnit。@lealcelderio谢谢您的建议。我不使用transactional的主要原因可能是我希望在运行测试组之后有一个填充的数据库。它有助于调试,也有助于填充客户端应用程序的数据。另一个原因是我觉得这不是它的目的。在我的业务逻辑中实现了事务之后,我将得到嵌套的事务,并且可能会遇到许多棘手的问题,因为它的大部分实现都是隐藏的。@gagansingh如果我能找到一种与spring合并的方法,那就太好了。你会在哪里添加这种逻辑?您会使用
@Sql
注释并将这些清理脚本保存在Sql文件中吗?也许可以在测试类中添加此注释?非常好的解决方案。谢谢:)我知道了