我使用TestContainers with Sping Boot 来运行存储库的单元测试,如下所示:
@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
,但没有帮助。
5条答案
按热度按时间aurhwmvo1#
如果你想拥有可重用的容器,你不能使用JUnit Jupiter注解
@Container
,这个注解确保停止容器after each test。您需要的是单例容器方法,例如使用
@BeforeAll
来启动您的容器。即使您在多个测试中使用.start()
,如果您选择使用容器定义中的.withReuse(true)
和主目录中的以下.testcontainers.properties
文件来实现可重用性,Testcontainers也不会启动新的容器:下面是一个简单的示例:
另一个集成测试:
型
目前有一个关于此的PR that adds documentation
我写了一篇博客文章详细解释了how to reuse containers with Testcontainers。
flvlnr442#
如果您决定继续使用单例模式,请注意“通过JDBCURL方案启动的数据库容器”中的警告。我花了几个小时才注意到,即使我使用的是单例模式,也总是会创建Map到不同端口的额外容器。
总之,如果需要使用单例模式,请不要使用测试容器JDBC(无主机)URI,如
jdbc:tc:postgresql:<image-tag>:///<databasename>
。hiz5n14c3#
可以接受的答案很好,但问题是您仍然必须为每个集成测试重复配置(创建、启动等)。使用更少的代码行进行更简单的配置会更好。我认为更干净的版本应该使用JUnit 5扩展。
这就是我解决这个问题的方法。下面的例子使用了MariaDB容器,但是这个概念适用于所有的容器。
1.创建容器配置保存类:
1.创建一个扩展类来启动容器并设置
DataSource
属性。如果需要,运行迁移:1.将
@ExtendWith
添加到测试类型
又一个测试
goucqfw64#
使用单例容器或可重用容器都是可能的解决方案,但因为它们没有将容器的生命周期限定在应用程序上下文的生命周期内,所以两者都不是理想的解决方案。
但是,可以通过使用
ContextCustomizerFactory
和I've written about this in more detail in a blog post将容器的范围限定为应用程序上下文生命周期。在测试使用中:
然后启用
META-INF/spring.factories
中的注解:其可以实现为:
型
q5lcpyga5#
我不确定
@Testcontainers
是如何工作的,但我怀疑它可能对每个类都有效。只要按照Singleton pattern中的描述使你的单例静态化,并在每个测试中从你的单例保持器那里得到它,不要在每个测试类中定义它。