java—使用带有junit5扩展的testcontainers

lrpiutwd  于 2021-07-08  发布在  Java
关注(0)|答案(1)|浏览(353)

我使用 Spring boot 以及 JUnit5 . 我的应用程序可用于多个数据库: MySQL , Clickhouse 等等。
为了进行集成测试,我创建了junit5扩展:

public class ClickHouseTestContainersExtension implements BeforeAllCallback, BeforeTestExecutionCallback {

    public static final String IMAGE_NAME = "registry.mycomp.com/db/clickhouse-server:20.5.3.27";

    @Container
    private static final FixedHostPortGenericContainer<?> clickHouse = new FixedHostPortGenericContainer<>(IMAGE_NAME)
            .withCopyFileToContainer(MountableFile.forClasspathResource("dbInitScripts/init_clickhouse.sql"), "/docker-entrypoint-initdb.d/init_clickhouse.sql")
            .withMinimumRunningDuration(Duration.ofSeconds(7))
            .withFixedExposedPort(8124, 8123);

    @Override
    public void beforeAll(ExtensionContext extensionContext) {
        startContainerIfNeed();
    }

    @Override
    public void beforeTestExecution(ExtensionContext extensionContext) {
        startContainerIfNeed();
    }

    public void startContainerIfNeed() {
        if (!clickHouse.isRunning()) {
            log.info("ClickHouse container is not running! Started.....");
            clickHouse.start();
        }
    }
}

和mysql:

public class MySQLTestContainersExtension implements BeforeAllCallback, BeforeTestExecutionCallback {

    private static final String IMAGE_NAME = "registry.mycomp.com/db/mariadb:10.4.11";

    @Container
    private static final FixedHostPortGenericContainer<?> mariaDb = new FixedHostPortGenericContainer<>(IMAGE_NAME)
            .waitingFor(new LogMessageWaitStrategy()
                    .withRegEx(".*ready for connections.*")
                    .withTimes(2)
                    .withStartupTimeout(Duration.of(3, MINUTES)))
            .withEnv("MYSQL_DATABASE", "db")
            .withEnv("MYSQL_USER", "sys")
            .withEnv("MYSQL_PASSWORD", "qwerty")
            .withEnv("MYSQL_ROOT_PASSWORD", "toor")
            .withEnv("MYSQL_RANDOM_ROOT_PASSWORD", "no")
            .withEnv("MYSQL_ALLOW_EMPTY_PASSWORD", "no")
            .withFixedExposedPort(33060, 3306)
            .withCopyFileToContainer(MountableFile.forClasspathResource("dbInitScripts/init_mysql.sql"),
                    "/docker-entrypoint-initdb.d/init_mysql.sql");

    @Override
    public void beforeAll(ExtensionContext extensionContext) {
        startContainerIfNeed();
    }

    @Override
    public void beforeTestExecution(ExtensionContext extensionContext) {
        startContainerIfNeed();
    }

    public void startContainerIfNeed() {
        if (!mariaDb.isRunning()) {
            log.info("MariaDB container is not running! Started.....");
            mariaDb.start();
        }
    }
}

以及其他一些类似的扩展。
我还有注解:

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
@ExtendWith({MySQLTestContainersExtension.class})
public @interface MySQL {
}

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
@ExtendWith({ClickHouseTestContainersExtension.class})
public @interface ClickHouse {
}

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
@ExtendWith({ClickHouseTestContainersExtension.class, MySQLTestContainersExtension.class,
        PostgreSQLTestContainersExtension.class, IgniteTestContainersExtension.class})
public @interface WithAllDatabases {
}

当我编写一些测试时,我使用这个扩展:

@Test
    @ClickHouse
    @DisplayName("Test connection ClickHouse with alive status")
    void testConnectionClickHouseWithAliveStatus() throws IOException {
        //smth
    }

    @Test
    @MySQL
    @DisplayName("Test connection MySQL with alive status")
    void testConnectionMariaDBWithAliveStatus() throws IOException {
        //smth
    }

  //etc

我的连接属性,如用户名、密码、url,存储在数据库中,而不是在aplication.yml中。我系统的任何用户,都可以手动添加新连接。
所以我不能用Spring机构 @DynamicPropertySource .
而且,我无法从扩展中获得生成的随机端口!
因此,我使用一个固定端口来创建一组测试连接,连接到在测试内容中引发的数据库!
告诉我是否有什么方法可以让你使用 JUnit 5 扩展并使用随机端口。我的任务是为一个特定的测试生成任何数据库,只需在这个测试上面添加一个注解。

tpxzln5u

tpxzln5u1#

我有几个问题
它是否工作,你只是想使用随机端口,而不是固定的或根本不工作?
我觉得你对这个要求太严格了。只是简单地在测试类/方法上放置一个注解并不是最终目的,因为您没有api来处理您的代码。据我所知,您不能访问扩展类中的任何内容(字段、方法)。我相信你会发现:
每个数据库容器都有一个单例工厂(turn) startContainerIfNeed() 并调用 MySQLTestContainersExtension.getContainer() 当你需要一个容器的时候
或者从扩展类中生成一个抽象类并在测试类中进行扩展,在这种情况下,您可以 mariaDb 变量static或使其成为常规字段并通过getter访问
@Container 在你的情况下什么都不做,你可以在这里读到

相关问题