简体   繁体   English

使用带有 JUnit5 扩展的测试容器

[英]Using Testcontainers with JUnit5 extensions

I using Spring boot and JUnit5 .我使用Spring bootJUnit5 My app work with several databases: MySQL , Clickhouse , etc.我的应用程序使用多个数据库: MySQLClickhouse等。

For integration testing, I created JUnit5 Extensions:对于集成测试,我创建了 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();
        }
    }
}

And MySQL:和 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();
        }
    }
}

And a number of other similar extensions.以及许多其他类似的扩展。

I also have annotations:我也有注释:

@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 {
}

And, When I write some test, I use this extension:而且,当我写一些测试时,我使用这个扩展:


    @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

My connections properties, like username, password, url, store in database, not in apllication.yml.我的连接属性,如用户名、密码、url,存储在数据库中,而不是在 apllication.yml 中。 Any user of my system, can mannualy add new connection.我系统的任何用户都可以手动添加新连接。

So I can't just use a spring mechanism like a @DynamicPropertySource .所以我不能只使用像@DynamicPropertySource这样的弹簧机制。

Moreover, I can't get the generated random port from the extension in any way!此外,我无法以任何方式从扩展中获取生成的随机端口!

Therefore, I use a fixed port to create a set of test connections to the database raised in the content in tests!因此,我使用固定端口创建了一组测试连接到数据库中提出的内容在测试中!

Tell me if there is some approach that will allow you to use the JUnit 5 extension and use a random port.告诉我是否有某种方法可以让您使用JUnit 5扩展并使用随机端口。 My task was to raise any database for a specific test by simply putting an annotation above this test.我的任务是通过简单地在此测试上方添加注释来为特定测试提升任何数据库。

I have a few questions我有几个问题

  1. Does it work and you just want to use random ports instead of fixed ones or does it not work at all?它是否有效,您只想使用随机端口而不是固定端口,还是根本不起作用?
  2. I think you follow the requirement too strictly.我认为您太严格地遵守要求。 Just making as easy as placing one annotation on a test class/method is not the final purpose, since you don't have an API to work with your code.像在测试类/方法上放置一个注释一样简单并不是最终目的,因为您没有 API 来处理您的代码。 And you can't access anything (fields, methods) inside the extension class as I understand.据我了解,您无法访问扩展类中的任何内容(字段、方法)。 I believe you might find it more convenient to either:我相信您可能会发现以下任一方式更方便:
  • have a singleton factory for each database container (turn startContainerIfNeed() into a factory method) and call MySQLTestContainersExtension.getContainer() when you need a container每个数据库容器都有一个单例工厂(将startContainerIfNeed()转换为工厂方法)并在需要容器时调用MySQLTestContainersExtension.getContainer()
  • or make an abstract class out of extension classes and extend it in your test classes, in this case you can either keep a mariaDb variable static or make it a regular field and access via getter或从扩展类中创建一个抽象类并在您的测试类中扩展它,在这种情况下,您可以保持mariaDb变量静态或使其成为常规字段并通过 getter 访问

Also @Container does not do anything in your case, you can read about it here此外,@ @Container对您的情况没有任何作用,您可以在此处阅读相关信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM