4、集成测试环境搭建:Docker Compose编排PostgreSQL与消息队列容器
集成测试环境的核心挑战在于:可重复性、隔离性与数据一致性。本章使用 Docker Compose 将 PostgreSQL 与消息队列(以 RabbitMQ 为例)编排为统一的测试栈,并重点解决网络互通、端口映射与持久化卷挂载三个关键问题。
4.1 环境拓扑与容器角色
测试环境由三个容器组成:PostgreSQL 数据库、RabbitMQ 消息队列、以及测试执行器(即你的集成测试进程)。Docker Compose 确保三者启动顺序正确、网络互通、数据持久化。
关键设计原则: 测试执行器不应直接依赖宿主机服务,所有依赖项(DB、MQ)均通过 Compose 声明式管理,保证 CI/CD 与本地环境行为一致。
4.2 Docker Compose 编排文件
以下 docker-compose.yml 定义了完整的测试环境。注意 depends_on 仅控制启动顺序,不保证服务就绪;因此需要配合健康检查(healthcheck)使用。
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: it-postgres
restart: unless-stopped
environment:
POSTGRES_DB: integration_test
POSTGRES_USER: tester
POSTGRES_PASSWORD: test_pass_2024
ports:
- "5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d
networks:
- integration_test_net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U tester -d integration_test"]
interval: 5s
timeout: 3s
retries: 5
rabbitmq:
image: rabbitmq:3.12-management-alpine
container_name: it-rabbitmq
restart: unless-stopped
environment:
RABBITMQ_DEFAULT_USER: tester
RABBITMQ_DEFAULT_PASS: test_pass_2024
ports:
- "5672:5672"
- "15672:15672"
volumes:
- rabbitmq_data:/var/lib/rabbitmq
networks:
- integration_test_net
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pg_data:
driver: local
rabbitmq_data:
driver: local
networks:
integration_test_net:
driver: bridge
4.3 网络配置详解
所有容器加入同一个自定义桥接网络 integration_test_net,实现容器间通过服务名直接通信。测试代码中数据库连接串与 MQ 连接串使用容器服务名而非 localhost。
| 配置项 | 值 | 说明 |
|---|---|---|
| 网络驱动 | bridge | 单机测试环境默认选择,提供 DNS 解析 |
| 容器间通信 | 服务名:端口 | 例如 postgres:5432、rabbitmq:5672 |
| 宿主机访问 | localhost:映射端口 | 仅用于调试工具(如 DBeaver、RabbitMQ 管理界面) |
| 网络隔离 | 独立子网 | 避免与宿主机其他容器冲突 |
最佳实践: 测试代码中数据库与 MQ 的连接地址应通过环境变量注入,而非硬编码。Compose 文件中使用
environment 或 .env 文件传递这些变量。
4.4 端口映射策略
端口映射遵循“最小暴露”原则:仅暴露测试执行器需要访问的端口到宿主机,管理端口仅在调试时暴露。
- PostgreSQL:5432 → 5432(数据库访问端口,必须暴露)
- RabbitMQ:5672 → 5672(AMQP 协议端口,必须暴露)
- RabbitMQ 管理界面:15672 → 15672(可选,调试用,CI 环境可关闭)
注意: 如果宿主机已占用 5432 或 5672 端口,请在 Compose 文件中修改左侧端口号(例如
"5433:5432"),并同步更新测试代码中的连接配置。
4.5 持久化卷配置
持久化卷保证容器重启后数据不丢失,同时支持测试数据回溯场景。每个服务使用独立命名卷,避免数据冲突。
| 卷名称 | 容器内挂载点 | 用途 |
|---|---|---|
| pg_data | /var/lib/postgresql/data | 存储数据库文件、WAL 日志、表空间 |
| rabbitmq_data | /var/lib/rabbitmq | 存储队列消息、交换机绑定、持久化消息 |
| ./init-scripts | /docker-entrypoint-initdb.d | 绑定挂载初始化 SQL 脚本(非持久化卷) |
4.6 初始化脚本与数据准备
在 ./init-scripts 目录下放置 SQL 初始化脚本,PostgreSQL 容器首次启动时会自动执行。这是构建测试基线数据的关键入口。
-- init-scripts/01_create_tables.sql
CREATE TABLE IF NOT EXISTS orders (
order_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS order_events (
event_id BIGSERIAL PRIMARY KEY,
order_id UUID REFERENCES orders(order_id),
event_type VARCHAR(50) NOT NULL,
payload JSONB,
occurred_at TIMESTAMPTZ DEFAULT NOW()
);
-- 插入基线数据
INSERT INTO orders (order_id, status) VALUES
('a1b2c3d4-0001-4000-8000-000000000001', 'PENDING'),
('a1b2c3d4-0002-4000-8000-000000000002', 'CONFIRMED');
4.7 启动与验证步骤
执行以下命令启动测试环境,并验证所有服务就绪:
# 启动所有容器(后台模式)
docker compose up -d
# 查看容器状态
docker compose ps
# 查看实时日志
docker compose logs -f
# 验证 PostgreSQL 就绪
docker compose exec postgres pg_isready -U tester -d integration_test
# 验证 RabbitMQ 就绪
docker compose exec rabbitmq rabbitmq-diagnostics check_port_connectivity
# 停止并清理(保留卷数据)
docker compose down
# 完全清理(删除卷数据)
docker compose down -v
4.8 常见问题与避坑指南
问题1:容器启动后测试连接失败
原因:PostgreSQL 或 RabbitMQ 尚未完成初始化(健康检查未通过)。
解决:在测试代码中添加重试机制,等待健康检查通过后再建立连接。
原因:PostgreSQL 或 RabbitMQ 尚未完成初始化(健康检查未通过)。
解决:在测试代码中添加重试机制,等待健康检查通过后再建立连接。
问题2:端口冲突导致容器无法启动
原因:宿主机已占用 5432 或 5672 端口。
解决:修改 Compose 文件中的左侧端口映射,或停止占用端口的进程。
原因:宿主机已占用 5432 或 5672 端口。
解决:修改 Compose 文件中的左侧端口映射,或停止占用端口的进程。
问题3:容器重启后数据丢失
原因:未正确配置持久化卷,或使用了
解决:确认
原因:未正确配置持久化卷,或使用了
docker compose down -v 清除了卷。解决:确认
volumes: 配置正确,日常使用 docker compose down(不带 -v)保留数据。
4.9 测试环境验证清单
在开始编写集成测试之前,逐项确认以下环境就绪状态:
| 检查项 | 验证命令 | 预期结果 |
|---|---|---|
| PostgreSQL 容器运行中 | docker compose ps postgres |
状态为 Up (healthy) |
| RabbitMQ 容器运行中 | docker compose ps rabbitmq |
状态为 Up (healthy) |
| 数据库连接正常 | docker compose exec postgres psql -U tester -d integration_test -c "SELECT 1" |
返回 1 行结果 |
| MQ 连接正常 | docker compose exec rabbitmq rabbitmqadmin -u tester -p test_pass_2024 list queues |
返回队列列表(可能为空) |
| 初始化数据存在 | docker compose exec postgres psql -U tester -d integration_test -c "SELECT count(*) FROM orders" |
返回 2 条记录 |
自动化建议: 将上述验证清单写入
Makefile 或 Shell 脚本,作为 CI 流水线的前置检查步骤,确保环境就绪后再执行集成测试。