在不启动测试容器的情况下运行 SpringBootTest 上下文

问题描述

我有 2 个父测试类:

@SpringBoottest(properties = {
        "spring.datasource.url=jdbc:tc:MysqL:8.0.25:///my_test_db?TC_INITSCRIPT=db/init_MysqL.sql","spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver"
})
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
public abstract class UserApplicationIntegrationTest {
}

@SpringBoottest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
public abstract class UserApplicationTest {
}

这个想法是让各种测试类扩展这些类。需要模拟 MysqL 数据库的那些将扩展 UserApplicationIntegrationTest。不需要数据库连接但需要 Spring 上下文的那些将扩展 UserApplicationTest。

在没有 UserApplicationIntegrationTest 的情况下,所有扩展 UserApplicationTest 的测试类都运行良好,包括使用 Mockito 框架。不幸的是,当我引入 UserApplicationIntegrationTest 及其子测试(与 dockerised db 实例完美配合)时,这些测试开始失败,因为它们突然需要一个数据源。

Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class

如果我尝试在应用程序属性父类的注释中排除数据源自动配置,则测试容器测试(那些扩展 UserApplicationIntegrationTest 的测试)由于 Spring 上下文的问题而开始失败,并且无法再自动装配 bean在这些测试中。

在我知道之前,我陷入了一个尝试凌乱的排除/添加的兔子洞中,我之前在以前的项目中遇到过这种情况,这只会导致更进一步的问题。

基本上我希望在我的项目中共存 3 种类型的测试:

  1. 没有 Spring 上下文的单元测试
  2. 使用 Spring 上下文进行单元测试(包括大量模拟但仍支持自动装配/构造函数注入)
  3. 使用 Spring 上下文进行集成测试,可启动测试容器并允许我测试数据库交互(以及可能进行的端到端测试)

我想避免为所有 Spring 上下文测试启动 testcontainers 的最初原因(这将“工作得很好”并且在构建过程中只包含 1 个 docker 延迟)是因为我不得不等待 MysqL每次我在开发过程中在本地运行单个 Spring 上下文测试时,都连接到 dockerised 实例。

是否有一种整洁的方式来实现这一目标,或者有一种更好的方式来浏览需求?

提前致谢。

解决方法

希望我理解你是对的,我所做的是实现一个抽象的 TestContainer 测试类:

package de.dwosch.it;

@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()
                );
            }
        }
    }

然后我只是通过这个抽象类扩展我的测试类,它将启动一个测试容器和整个 spring 上下文以更好地分离

class MyAwesomeControllerIT extends AbstractPostgreSQLTestContainerIT { }