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

     2023-03-28     269

关键词:

【中文标题】使用带有 JUnit5 扩展的测试容器【英文标题】:Using Testcontainers with JUnit5 extensions 【发布时间】:2021-03-07 01:39:56 【问题描述】:

我使用Spring bootJUnit5。我的应用适用于多个数据库:MySQLClickhouse 等。

为了集成测试,我创建了 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 中。我系统的任何用户都可以手动添加新连接。

所以我不能只使用像@DynamicPropertySource 这样的弹簧机制。

而且,我无法以任何方式从扩展中获取生成的随机端口!

因此,我使用一个固定端口来创建一组测试连接到测试中内容中提出的数据库!

告诉我是否有某种方法可以让您使用JUnit 5 扩展名并使用随机端口。我的任务是通过简单地在该测试上方添加注释来为特定测试提升任何数据库。

【问题讨论】:

【参考方案1】:

我有几个问题

    它是否有效,而您只是想使用随机端口而不是固定端口,还是根本无效? 我认为你对要求的要求太严格了。就像在测试类/方法上放置一个注释一样简单并不是最终目的,因为您没有 API 来处理您的代码。据我了解,您无法访问扩展类中的任何内容(字段、方法)。 我相信您可能会发现以下任一方式更方便:
每个数据库容器都有一个单例工厂(将startContainerIfNeed() 转换为工厂方法)并在需要容器时调用MySQLTestContainersExtension.getContainer() 或从扩展类中创建一个抽象类并在您的测试类中扩展它,在这种情况下,您可以将mariaDb 变量保持为静态或使其成为常规字段并通过 getter 访问

另外@Container 对你的情况没有任何作用,你可以阅读它here

【讨论】:

带有 @Suite 注释的 Junit5 测试套件不使用 mvn test 命令执行测试

】带有@Suite注释的Junit5测试套件不使用mvntest命令执行测试【英文标题】:Junit5testsuiteswith@Suiteannotationdoesn\'texecutetestswithmvntestcommand【发布时间】:2022-01-1420:24:28【问题描述】:我们打算将基于JUnit4的项目升级到JUnit5。我根据JUnit5... 查看详情

使用 Micronaut 应用程序为 JUnit5 中的每个单元/集成测试运行一次 TestContainer

】使用Micronaut应用程序为JUnit5中的每个单元/集成测试运行一次TestContainer【英文标题】:RunningTestContaineronceforeachUnit/IntegrationtestinJUnit5withMicronautapplication【发布时间】:2021-10-1707:33:55【问题描述】:我在Micronaut应用程序中使用带... 查看详情

带有测试 application.properties 的 Junit 5

...:27:16【问题描述】:我正在学习Junit5和测试用例。我正在使用SpringBoot版本\'2.2.6.RELEASE和JUnit5,在我的应用程序中,我有一个基于属性文件中的布尔标志进行处理的方法。\\src\\main\\resource 查看详情

为啥 Spring Boot 使用单例容器方法生成 2 个测试容器?

】为啥SpringBoot使用单例容器方法生成2个测试容器?【英文标题】:WhydoesSpringBootspawn2testcontainerswithsingletoncontainerapproach?为什么SpringBoot使用单例容器方法生成2个测试容器?【发布时间】:2021-10-2802:16:06【问题描述】:我正在使用... 查看详情

如何使用 junit5 和 testcontainers 测试存储库?

】如何使用junit5和testcontainers测试存储库?【英文标题】:Howtotestrepositorywithjunit5andtestcontainers?【发布时间】:2021-02-1016:21:15【问题描述】:我有一个示例项目,我在其中试验不同的技术。我有以下设置:SpringBoot2.3.4.RELEASE飞路7.0... 查看详情

在 Junit 5 中,如何从扩展中调用测试类方法?

...:在Junit5中,我试图让测试类方法从扩展中运行。我正在使用Junit5扩展接口TestWatcher并覆盖testFailed()方法。此扩展的目的是在测试类的SeleniumWebDriver浏览器中截取失败 查看详情

测试容器在 Spring Boot 项目中启动两个容器而不是一个

...roject【发布时间】:2021-09-0504:27:02【问题描述】:我正在使用带有SpringBoot2.4和Junit5的Testcontainers1.15.3。当我运行测试时,testcontainers会启动第一个容器并执行flyway 查看详情

springboot集成junit5,更优雅单元测试!(代码片段)

来源:https://www.cnblogs.com/haixiang/p/13812363.html 为什么使用JUnit5JUnit4被广泛使用,但是许多场景下使用起来语法较为繁琐,JUnit5中支持lambda表达式,语法简单且代码不冗余。JUnit5易扩展,包容性强,可以接入... 查看详情

JUnit 5 和具有不同扩展的继承,用于使用 TestContainers 进行 Spring Boot 集成测试

】JUnit5和具有不同扩展的继承,用于使用TestContainers进行SpringBoot集成测试【英文标题】:JUnit5andinheritancewithdifferentextensionsforSpringBootIntegrationtestwithTestContainers【发布时间】:2021-08-2116:50:30【问题描述】:简介:我们的产品需要对3... 查看详情

junit5安装与使用

...月份推出,目前最新版5.0.1。几乎所有的Java开发人员都会使用JUnit来做测试,但其实很多自动化测试人员也会使用Junit。目前,Android单元测试默认使用Junit4,相信不久的将来也会使用JUnit5。但是介绍JUnit5 安装与使用资料并不... 查看详情

junit5与自动化测试

JUnit5由三个不同的模块组成。第一个模块是JUnit平台,其主要作用是在JVM上启动测试框架。它定义了一个抽象的TestEngineAPI来定义运行在平台上的测试框架,同时还支持通过命令行、Gradle和Maven来运行平台。第二个模块是JUnitJupiter... 查看详情

使用 Junit5 进行测试时位置对象返回 null

】使用Junit5进行测试时位置对象返回null【英文标题】:LocationobjectreturnnullwhiletestingwithJunit5【发布时间】:2021-04-2703:28:14【问题描述】:我必须测试当前位置是否在某个特定位置附近。在我的测试类中,我试图通过设置经度和纬... 查看详情

我可以在 JDBC URL 模式下使用带有自定义 Dockerfile 的 Testcontainers 吗?

】我可以在JDBCURL模式下使用带有自定义Dockerfile的Testcontainers吗?【英文标题】:CanIuseTestcontainersinJDBCURLmodewithacustomDockerfile?【发布时间】:2020-02-0620:33:49【问题描述】:我正在测试一个SpringBoot应用程序并尝试使用Testcontainers在Doc... 查看详情

java应用xviii在java中使用junit5进行单元测试和自动化测试

...nit5是Java中流行的单元测试框架,本文将介绍如何在Java中使用JUnit5进行单元测试和自动化测试。二、单元测试2.1单元测试的基本概念和原理单元测试是一种测试方法,用于对软件系统中的最小可测试单元进行测试。这些单元通常... 查看详情

使用 Spring Boot 和 JUnit5 在 Intellij 中终止所有测试

】使用SpringBoot和JUnit5在Intellij中终止所有测试【英文标题】:AlltestsgetterminatedinIntellijwithSpringBootandJUnit5【发布时间】:2020-09-1921:45:29【问题描述】:我试图在我的SpringBoot应用程序中使用JUnit5编写一个简单的测试,但我注意到我... 查看详情

带有 docker 容器的 bitbucket 管道

...发布时间】:2019-07-0908:42:19【问题描述】:我有一个正在使用maven构建的项目。测试用例使用测试容器来启动一个MS-SQLserver实例。管道目前正在失败。我使用的管道图像的原因是:image:maven:3.6.0没有docker和sqlserver镜像。我的问题... 查看详情

如何使用 SpringBoot2、JUnit5 和 Kotlin 将配置属性注入单元测试

】如何使用SpringBoot2、JUnit5和Kotlin将配置属性注入单元测试【英文标题】:HowcanIinjectconfigpropertiesintoaunittest,usingSpringBoot2,JUnit5,andKotlin【发布时间】:2018-12-2202:03:35【问题描述】:我的场景:我正在构建一个使用Kotlin和SpringBoot2.0.3... 查看详情

springboot2---单元测试(junit5)(代码片段)

单元测试JUnit5的变化JUnit5常用注解常用注解使用演示断言机制(assertions)1、简单断言2、数组断言3、组合断言4、异常断言5、超时断言6、快速失败4、前置条件(assumptions)5、嵌套测试6、参数化测试Junit4到Junit5的迁移指南JUn... 查看详情