如何在多个 SpringBootTests 之间重用 Testcontainers?

Posted

技术标签:

【中文标题】如何在多个 SpringBootTests 之间重用 Testcontainers?【英文标题】:How to reuse Testcontainers between multiple SpringBootTests? 【发布时间】:2020-10-07 01:42:38 【问题描述】:

我正在使用带有 Spring Boot 的 TestContainers 为这样的存储库运行单元测试:

@Testcontainers
@ExtendWith(SpringExtension.class)
@ActiveProfiles("itest")
@SpringBootTest(classes = RouteTestingCheapRouteDetector.class)
@ContextConfiguration(initializers = AlwaysFailingRouteRepositoryShould.Initializer.class)
@TestExecutionListeners(listeners = DependencyInjectionTestExecutionListener.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Tag("docker")
@Tag("database")
class AlwaysFailingRouteRepositoryShould 

  @SuppressWarnings("rawtypes")
  @Container
  private static final PostgreSQLContainer database =
      new PostgreSQLContainer("postgres:9.6")
          .withDatabaseName("database")
          .withUsername("postgres")
          .withPassword("postgres");

但现在我有 14 个这样的测试,每次运行测试时都会启动一个新的 Postgres 实例。是否可以在所有测试中重用相同的实例? Singleton pattern 无济于事,因为每次测试都会启动一个新应用程序。

我也在.testcontainers.properties.withReuse(true) 中尝试过testcontainers.reuse.enable=true,但这没有帮助。

【问题讨论】:

你试过 withReuse(true) 选项了吗? @P3trur0:是的。而testcontainers.reuse.enable=true - 没有帮助。 尝试将容器实例作为@Bean 放入单独的@TestConfiguration,然后在所有相关测试中导入此配置。 @NikolaiShevchenko:试过了,但 @ContextConfiguration(initializers 需要它,我无法让它在那里工作。 【参考方案1】:

如果您想拥有可重用的容器,则不能使用 JUnit Jupiter 注释 @Container。此注解确保停止容器after each test。

您需要的是单例容器方法,并使用例如@BeforeAll 启动您的容器。即使您随后在多个测试中拥有.start(),如果您选择在容器定义中同时使用.withReuse(true) 和主目录中的以下.testcontainers.properties 文件以实现可重用性,Testcontainers 也不会启动新容器:

testcontainers.reuse.enable=true

一个简单的例子可能如下所示:

@SpringBootTest
public class SomeIT 

  public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
    withReuse(true);

  @BeforeAll
  public static void beforeAll() 
    postgreSQLContainer.start();
  

  @Test
  public void test() 

  


还有另一个集成测试:

@SpringBootTest
public class SecondIT 

  public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
    withReuse(true);

  @BeforeAll
  public static void beforeAll() 
    postgreSQLContainer.start();
  

  @Test
  public void secondTest() 

  


目前有一个PR that adds documentation关于这个

我整理了一篇博文,详细解释了how to reuse containers with Testcontainers。

【讨论】:

非常感谢。然后我还需要用.withCommand("postgres -c max_connections=200") 增加我的max_connections。如何控制可重用容器的生命周期? 我无法回答这个问题。也许值得看看介绍该功能的 PR:github.com/testcontainers/testcontainers-java/pull/1781 testcontainers.reuse.enable=true 记录在哪里? 是的,有多种方法可以配置此属性。查看 Testcontainers 文档的Configuration locations section。 你不能通过类路径设置testcontainers.reuse.enable。 See this comment.【参考方案2】:

如果您决定继续使用singleton pattern,请注意“Database containers launched via JDBC URL scheme”中的警告。我花了几个小时才注意到,即使我使用的是singleton pattern,总是会创建一个额外的容器,映射到不同的端口。

总之,不要使用测试容器的 JDBC (host-less) URI,例如 jdbc:tc:postgresql:<image-tag>:///<databasename>,如果你需要使用 singleton pattern。

【讨论】:

【参考方案3】:

我不确定@Testcontainers 的工作原理,但我怀疑它可能对每个班级都有效。

只需按照Singleton pattern 中的说明将您的单例设为静态即可 并从你的signleton持有者的每个测试中获取它,不要在每个测试类中定义它。

【讨论】:

“单例模式没有帮助,因为每个测试都会启动一个新应用程序。”

以上是关于如何在多个 SpringBootTests 之间重用 Testcontainers?的主要内容,如果未能解决你的问题,请参考以下文章

如何为不同的应用程序运行相同的 SpringBootTests

分布式的几件小事dubbo如何做服务治理服务降级以及重试

当我在文件类型之间切换时,如何取消重映射?

CCNP路由实验之八 路由重发布

如何解决具有多个其余端点的Brakeman重定向问题

如何合并多个工作表并用工作表名称重命名列名?