You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试类执行完毕后容器Destroy方法未调用的解决方案咨询

问题:嵌入式测试容器关闭时机与@Nested测试冲突问题

我在测试中使用了嵌入式容器,包括Kafka、PostgreSQL、Minio等,依赖配置如下:

<dependency>
    <groupId>com.playtika.testcontainers</groupId>
    <artifactId>embedded-kafka</artifactId>
</dependency>
<dependency>
    <groupId>com.playtika.testcontainers</groupId>
    <artifactId>embedded-postgresql</artifactId>
</dependency>
<dependency>
    <groupId>com.playtika.testcontainers</groupId>
    <artifactId>embedded-mssqlserver</artifactId>
</dependency>
<dependency>
    <groupId>com.playtika.testcontainers</groupId>
    <artifactId>embedded-minio</artifactId>
</dependency>

我通过自定义注解@EnableTestContainers启动测试类所需的容器,但测试完成后,Docker中的容器并未停止,而是一直运行到所有测试类执行完毕。

尝试添加配置embedded.containers.force-shutdown=true,但因Spring上下文的原因未生效,容器仍仅在所有测试运行结束后才关闭。

尝试添加@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS),该注解能在类执行后正常关闭容器,但会破坏@Nested测试的逻辑——我已有大量基于@Nested类编写的测试,它们依赖父类上下文。

现提出两个问题:

  1. 如何在不使用@DirtiesContext的情况下,在测试类执行完毕后关闭容器,且不影响@Nested测试?
  2. 如果必须使用@DirtiesContext注解,如何让它仅作用于父类,不在嵌套类执行后清理上下文?

解决方案

问题1:不使用@DirtiesContext实现容器按需关闭

方案1:自定义容器生命周期处理器

利用Playtika Testcontainers的扩展机制,自定义TestExecutionListener,在整个测试类(含所有@Nested子类)执行完成后手动触发容器关闭:

import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import com.playtika.testcontainers.spring.EmbeddedContainersContextCustomizer;

public class EmbeddedContainerShutdownListener implements TestExecutionListener {

    @Override
    public void afterTestClass(TestContext testContext) throws Exception {
        EmbeddedContainersContextCustomizer customizer = testContext.getApplicationContext()
                .getBean(EmbeddedContainersContextCustomizer.class);
        customizer.stop();
    }
}

在测试父类上注册该监听器:

@TestExecutionListeners(listeners = EmbeddedContainerShutdownListener.class, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
@EnableTestContainers
public abstract class BaseIntegrationTest {
    // 父类通用逻辑
}

afterTestClass方法会在所有嵌套测试执行完毕后触发,既保证容器及时关闭,又不破坏嵌套类对父类上下文的依赖。

方案2:调整Playtika容器配置

通过配置让容器绑定测试类生命周期,而非全局Spring上下文:
在application-test.properties中添加:

embedded.containers.per-test-container=true
embedded.containers.shutdown-on-context-close=true

该配置会为每个测试类创建独立容器实例,测试类(含所有嵌套子类)执行完毕后,容器随类级资源释放自动关闭,嵌套类可正常复用父类容器。

问题2:使用@DirtiesContext但不影响@Nested测试

方案1:父类设置@DirtiesContext并指定层级模式

在父类添加注解时,设置hierarchyMode = DirtiesContext.HierarchyMode.EXHAUSTIVE,确保仅在整个测试类层级(含所有嵌套类)执行完毕后才清理上下文:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS, hierarchyMode = DirtiesContext.HierarchyMode.EXHAUSTIVE)
@EnableTestContainers
public abstract class BaseIntegrationTest {
    // 父类通用逻辑
}

EXHAUSTIVE模式会忽略嵌套类的上下文脏标记,仅在父类生命周期结束时触发清理。

方案2:嵌套类覆盖@DirtiesContext配置

在每个@Nested类上添加@DirtiesContext(classMode = DirtiesContext.ClassMode.NEVER),明确禁止嵌套类触发上下文清理:

@Nested
@DirtiesContext(classMode = DirtiesContext.ClassMode.NEVER)
class NestedTest {
    // 嵌套测试逻辑
}

这种方式无需修改父类配置,直接在已有嵌套类上补充注解即可保留父类的AFTER_CLASS清理逻辑。


内容的提问来源于stack exchange,提问作者Andrew Bessonov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:27:47