如何使用JUnit、Spring Boot和Flyway进行测试?

3

如何正确地使用Junit实现Flyway?

我将Flyway添加到我的项目中,并将V1__init.sql(例如)放入**main**/resources/db/migration目录中。只要我调试代码(不进行测试),它就可以工作。

我必须将*.sql文件复制到**test**/resources/db/migration目录中吗?

我还希望测试针对的是另一个数据库,而不是测试数据库。我是否正确,必须在test文件夹下添加另一个application.properties文件,在其中输入用于构建数据库的凭据(测试运行的数据库)?

如果有人能帮助我理解如何正确配置它,我会非常高兴。

Image of where the files where placed.


1
您可以使用 src 文件夹下的迁移。当运行 @SpringBootTest 时,它们将被使用。因此无需复制它们。此外,您可以使用 TestContainers 对真实数据库实现集成测试,这将依赖于默认的 application.properties。 - Daniel Rafael Wosch
我了解到testcontainers,但是发现只有postgresql版本,没有mysql版本,我可能想再看一下,谢谢。我甚至认为它会从主文件夹中选择*.sql文件,但实际上我遇到了一个错误,说找不到迁移文件。我将更新我的问题,也许放置文件存在错误? - KaijuDeluxe
1个回答

6

您可以将迁移文件保留在src下,无需将其复制到测试文件夹中。当运行@SpringBootTest时,它们将被使用。这也确保您在测试中使用所有的production迁移。

此外,您不一定需要一个单独的属性文件进行测试。但是您可以有一个。

以下是使用TestContainers进行集成测试的示例,它使用application.properties和Flyway迁移,以便测试的行为与正常运行应用程序时相同。

这是一个抽象类,它确保测试在整个Spring上下文中运行,因此也涉及Flyway。在初始化器中,数据源配置属性被来自TestContainers数据库的属性覆盖。通过这样做,您直接使用真实的application.properties并模拟了一点真实情况;))

@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = AbstractPostgreSQLTestContainerIT.Initializer.class)
@Testcontainers
public abstract class AbstractPostgreSQLTestContainerIT {
    private static final String POSTGRES_VERSION = "postgres:11.1";
    public static PostgreSQLContainer database;

    static {
        database = new PostgreSQLContainer(POSTGRES_VERSION);
        database.start();
    }

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
                    configurableApplicationContext,
                    "spring.datasource.url=" + database.getJdbcUrl(),
                    "spring.datasource.username=" + database.getUsername(),
                    "spring.datasource.password=" + database.getPassword()
            );
        }
    }
}

现在你可以像下面这样定义多个测试类:

class MyIntegrationTest extends AbstractPostgreSQLTestContainerIT { }

当运行此类中的测试时,SpringBoot应用程序会启动并使用TestContainers数据库。
为了我的目的,我还实现了一个简单的注释:
void updateFooByExternalIdentifier_DTOProvided_ShouldReturnUpdatedFoo() {}

代码

/**
 * Annotation which allows to provide SQL Scripts for a certain IT test.
 * The transactional ensures that data is cleaned up after test.
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Test
@Sql
public @interface TransactionalSQLTest {
    @AliasFor(attribute = "value", annotation = Sql.class)
    String[] value() default {};

    @AliasFor(attribute = "executionPhase", annotation = Sql.class)
    Sql.ExecutionPhase executionPhase() default Sql.ExecutionPhase.BEFORE_TEST_METHOD;
}

使用注释,您可以为测试提供SQL示例数据。 pom.xml文件。
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>${testcontainers.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <version>${testcontainers.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>${testcontainers.version}</version>
    <scope>test</scope>
</dependency>

这应该是 MySql 的依赖项

<!-- https://mvnrepository.com/artifact/org.testcontainers/mysql -->
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>mysql</artifactId>
    <version>1.15.3</version>
    <scope>test</scope>
</dependency>

非常感谢!听起来很不错,我使用了像下面代码一样的MySqlContainer进行了测试,但是出现了一个错误:“您没有SUPER特权并且启用了二进制日志记录”。你知道问题可能是什么吗?Docker看起来很棒,我可能会花些时间学习更多关于它的知识。 - KaijuDeluxe
1
你是否在Linux下运行?如果我记得正确,那么你正在使用的用户需要添加到特定组中才能运行IDE。否则,docker容器将无法启动。另外:你是否安装了docker?如果没有安装,则必须安装它,因为TestContainers基于docker。 - Daniel Rafael Wosch
我正在使用MacOS并安装了Docker。当我创建数据库时,如database = new MySQLContainer();,它可以工作,但这个构造函数已被弃用。我理解的是否正确,Docker MySQL实例仅供测试使用?在开发例如新视图时,我应该使用我的本地数据库(因此不同于测试所使用的)? - KaijuDeluxe
1
当然。你应该只在测试目的下使用测试容器,因为数据库会在测试后被销毁。但是你可以使用Docker来创建本地数据库。 - Daniel Rafael Wosch
哇!太棒了。它完美地运行了 :-D 只需要找出如何在不使用已弃用的构造函数的情况下获取数据库。在我的应用程序中,我需要一些数据,例如“下载路径”和其他必须在数据库中的东西,我认为通过 flyway 初始化这些数据是一个好方法,那么测试容器也将被填充这些数据。 - KaijuDeluxe
1
您可以在静态初始化器中配置初始数据,例如 SQL 文件到 TestContainer。应该有相应的修改器方法。 - Daniel Rafael Wosch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接