弹簧启动和飞行路线:在集成测试之前清除数据库数据

2022-09-03 05:28:02

我正在使用Spring引导框架(v2.0.2)构建REST服务,其中我在数据库上运行集成测试。我在谷歌上搜索了很多,在测试之前有大量关于清理数据库的文章,但不幸的是,我发现它们要么效率低下,要么是黑客攻击,而不是Spring boot。你能不能容忍我,并提出一个好办法来解决这个问题?

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

@Autowired
protected Flyway flyway;

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

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

有没有一些好的方法可以从静态上下文中到达这个飞行方式的豆子,以使这个解决方案起作用?

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

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

谢谢!


答案 1

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

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

答案 2

这个答案很有用,但它并没有让我一路走到那里,所以我想我会回来添加一个答案,以防其他人想要解决同样的问题。上面的豆类定义非常棒。

弹簧轮廓有5种左右的可能性。我查看了文档以及人们如何使用它们,但走了另一条路。Maven 有 6 个作用域,但在这种情况下有用的作用域是运行时和测试。

当我深入研究弹簧轮廓以及可以在它们之间切换的各种方式时,对于我的情况来说,这似乎有点太复杂了。我只想创建、筛选和填充一些数据,以便我可以在 jpa spring boot 应用中测试存储库。我不想花 4 个小时设置个人资料。并不是说从长远来看,这不是一个值得的努力,只是我想让事情发展起来。

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

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

上面的答案使我找到了一个解决方案,随着我的项目越来越接近生产,我可能会将其折叠成弹簧型材。

事实证明,spring-boot-test提供了一个@TestConfiguration注释,您可以将其附加到src/test/层次结构中的任何类。我创建了一个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;

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

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

另外:src/main/resources 将 jdbc 和 flyway 属性设置为开发模式名称和 jdbc url。

src/test/resources/application.properties 将架构名称设置为“test”(您可以根据需要对其进行命名)。

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

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


推荐