使用Playwright与Node Testcontainers重启Postgres容器报错求助
问题
使用Playwright结合Node Testcontainers在Docker容器中运行测试,需求如下:
- API容器仅启动一次,所有测试完成后再停止
- 每个测试执行前重启Postgres数据库容器
当前调整配置后出现错误:(HTTP code 409) container stopped/paused failed to create Container,数据库容器似乎在测试启动前就已退出。
现有代码
let databaseContainer; let apiContainer; let network test.beforeAll(async () => { network = await new Network().withName("test"); apiContainer = await new GenericContainer('apicontainer:1.0') .withName('api') .withEnvironment({ ASPNETCORE_ENVIRONMENT: 'Development' }) .withEnvironment({ CONNECTIONSTRINGS_POSTGRES: 'Host=postgres;Username=admin;Password=admin;Database=Test', }) .withEnvironment({ CONNECTIONSTRINGS__POSTGRES: 'Host=postgres;Username=admin;Password=admin;Database=Test', }) .withExposedPorts({ container: 80, host: 1234 }).start(); }); test.beforeEach(() => { databaseContainer = await new PostgreSqlContainer('postgres:14.6') .withName('database') .withNetworkMode(network.getName()) .withEnvironment({ POSTGRES_USER: 'admin' }) .withEnvironment({ POSTGRES_PASSWORD: 'admin' }) .withEnvironment({ POSTGRES_DB: 'Test' }) .withDatabase('Test') .withExposedPorts({ container: 5432, host: 5432 }); .withNetworkMode(network.getName)) .start(); }) test.afterEach(() => { await databaseContainer.stop(); }) test.afterAll(async () => { await apiContainer.stop(); })
问题分析与修复方案
核心错误点
语法错误:
withExposedPorts语句末尾多了分号,导致后续withNetworkMode调用报错network.getName)少了括号,应为network.getName()- 重复调用
withNetworkMode,属于冗余配置
异步逻辑缺失:
beforeEach和afterEach未声明为async函数,内部的await无法生效,容器操作未完成就进入下一步,导致容器状态异常。容器命名与端口冲突:
- 固定使用
database作为容器名,旧容器未完全销毁时,新容器创建会触发Docker的同名冲突(409错误) - 固定绑定主机端口5432,旧容器未释放端口时,新容器启动失败
- 固定使用
网络关联错误:API容器未加入测试网络
test,导致API无法访问Postgres容器,可能引发数据库容器因连接问题提前退出。数据库就绪等待缺失:未等待Postgres容器完全启动就绪就开始测试,可能导致测试执行时数据库不可用,容器异常退出。
修复后的代码
let databaseContainer; let apiContainer; let network; test.beforeAll(async () => { // 创建测试专用网络并启动 network = await new Network().withName("test").start(); // 启动API容器并加入测试网络 apiContainer = await new GenericContainer('apicontainer:1.0') .withName('api') .withNetwork(network) // 将API容器加入测试网络 .withEnvironment({ ASPNETCORE_ENVIRONMENT: 'Development', CONNECTIONSTRINGS_POSTGRES: 'Host=postgres;Username=admin;Password=admin;Database=Test', CONNECTIONSTRINGS__POSTGRES: 'Host=postgres;Username=admin;Password=admin;Database=Test' }) .withExposedPorts(80) // 不固定主机端口,由Testcontainers自动分配 .start(); }); // 每个测试前启动新的Postgres容器 test.beforeEach(async () => { databaseContainer = await new PostgreSqlContainer('postgres:14.6') .withNetwork(network) // 加入测试网络 .withEnvironment({ POSTGRES_USER: 'admin', POSTGRES_PASSWORD: 'admin', POSTGRES_DB: 'Test' }) .withDatabase('Test') .withExposedPorts(5432) // 自动分配主机端口 .waitForHealthCheck() // 等待数据库健康检查通过 .start(); }); // 每个测试后停止并移除数据库容器 test.afterEach(async () => { await databaseContainer.stop(); await databaseContainer.remove(); // 确保容器被完全移除,避免命名冲突 }); test.afterAll(async () => { await apiContainer.stop(); await apiContainer.remove(); await network.remove(); // 清理测试网络 });
关键优化说明
- 移除固定容器名和主机端口,避免冲突,由Testcontainers自动管理资源
- 确保所有涉及异步操作的钩子函数都声明为
async - 为API容器和数据库容器加入同一测试网络,保证服务间可访问
- 增加
waitForHealthCheck()确保Postgres完全就绪后再执行测试 - 在
afterEach和afterAll中主动移除容器和网络,彻底清理资源
内容的提问来源于stack exchange,提问作者CenterADiv
相关产品推荐
相关产品推荐

