1

我有一个示例项目,我在其中尝试不同的技术。

我有以下设置:

  • Spring Boot 2.3.4.RELEASE
  • 飞路 7.0.1
  • 测试容器 1.15.0-rc2
  • Junit 5.7.0

如何使用 testcontainer-junit5 测试存储库层?

我现在拥有的代码示例CompanyRepositoryTest.java

@ExtendWith(SpringExtension.class)
@Testcontainers
public class CompanyRepositoryTest {

    @Autowired
    private CompanyRepository companyRepository;

    @Container
    public MySQLContainer mysqlContainer = new MySQLContainer()
            .withDatabaseName("foo")
            .withUsername("foo")
            .withPassword("secret");;

    
    @Test
    public void whenFindByIdExecuted_thenNullReturned()
            throws Exception {
        assertEquals(companyRepository.findById(1L), Optional.ofNullable(null));
    }

    @Test
    public void whenFindAllExecuted_thenEmptyListReturned() {
        assertEquals(companyRepository.findAll(), new ArrayList<>());
    }
}

添加时@SpringBootTest,我需要设置所有上下文并遇到一些应用程序加载上下文问题?

问题是,任何人都可以揭开@TestContainers注释的神秘面纱吗?在测试存储库时使用它的最佳实践或正确方法是什么?

4

4 回答 4

3

注解提供的JUnit 5 扩展@Testcontainers扫描使用注解声明的任何容器@Container,然后启动和停止这些容器以进行测试。作为静态字段的容器将与所有测试共享,作为实例字段的容器将为每个测试启动和停止。

如果您使用 Spring Boot,为测试设置测试容器的最简单方法可能是在application-test.yml. 这将使用数据源 JDBC URL 来启动 testcontainers 容器。有关更多信息,请参阅 Testcontainers JDBC 支持

您还可以使用@DataJpaTest而不是仅测试存储库层@SpringBootTest

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ActiveProfiles("test")
class CompanyRepositoryTest { }

你的application-test.yml文件:

spring:
  datasource:
    url: jdbc:tc:mysql:8.0://hostname/databasename
    driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver

在某些情况下,您可能还想使用@TestPropertySource注释:

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource(
    properties = {
        "spring.datasource.url = jdbc:tc:mysql:8.0://hostname/test-database",
        "spring.datasource.driver-class-name = org.testcontainers.jdbc.ContainerDatabaseDriver"
    }
)
class CompanyRepositoryTest { }

请注意hostnameandtest-database实际上并没有在任何地方使用。

于 2020-10-28T13:04:20.840 回答
2

你说

当我添加@SpringBootTest 时,我需要设置所有上下文并且有一些应用程序加载上下文问题?

如果您想尝试替代方案并且 Testcontainer 不是强制性的,您可以采用不同的方式。

使用 SpringBootTest 注解时不需要加载所有内容,可以指定需要哪些类,例如

@SpringBootTest(classes = { TheService.class })

或使用@Import注释

并嘲笑其他人,例如

@MockBean
MyService service;

对于数据库连接,您可以使用注释,例如

@ActiveProfiles("my-profile-for-jpa-test")
@DataJpaTest
@EnableJpaAuditing
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)

编辑:我觉得这应该是一个评论,但我想用正确的格式解决问题的 SpringBootTest 部分

于 2020-10-28T10:15:55.467 回答
1

这是一个示例,我如何在 Spring 中使用 MySql 配置 Liquibase(与 Flyway 类似的框架):

@DataJpaTest
@TestPropertySource(properties = {"spring.jpa.hibernate.ddl-auto=validate"})
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = { MySqlLiquibaseBaseIT.Initializer.class })
@Testcontainers
public class MySqlLiquibaseBaseIT {

  @Container
  public static MySQLContainer<?> mysql = new MySQLContainer<>(
    DockerImageName
      .parse(MySQLContainer.NAME)
      .withTag("5.7.22"));

  @Configuration
  @EnableJpaRepositories
  @EntityScan
  static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
      TestPropertyValues.of(
        "spring.datasource.url=" + mysql.getJdbcUrl(),
        "spring.datasource.username=" + mysql.getUsername(),
        "spring.datasource.password=" + mysql.getPassword(),
        "spring.datasource.driver-class-name=" + mysql.getDriverClassName())
        .applyTo(configurableApplicationContext.getEnvironment());
    }

    @Bean
    public SpringLiquibase springLiquibase(DataSource dataSource) {
      SpringLiquibase liquibase = new SpringLiquibase();
      liquibase.setDropFirst(true);
      liquibase.setDataSource(dataSource);
      liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.yml");
      return liquibase;
    }
  }
}

完整的 MySqlLiquibaseBaseIT.java

于 2021-05-05T11:37:57.440 回答
0
  1. 根据文档

测试容器扩展查找所有使用 Container 注释的字段并调用它们的容器生命周期方法。声明为静态字段的容器将在测试方法之间共享。它们只会在任何测试方法执行之前启动一次,并在最后一个测试方法执行后停止。声明为实例字段的容器将为每个测试方法启动和停止。

因此,在您的情况下,它将为每个测试方法重新创建一个容器,它只负责启动和停止容器。如果您需要一些测试数据 - 必须手动完成,因为我看到您有 Flyway,应该这样做。

  1. 你在说什么“背景问题”?

  2. 存储库通常不单独测试,您可以只测试运行存储库方法的服务,而不是为两者编写测试。如果您仍然想测试 repos - 在数据库中填充一些数据@Before

如果您有更多问题,请提出。

于 2020-10-28T11:53:25.113 回答