4. 测试环境搭建:Docker Compose 编排 PostgreSQL 与 Redis 服务

在集成测试中,环境的一致性与可重复性是保障测试质量的基础。本章将使用 Docker Compose 对 PostgreSQL(数据持久层)与 Redis(缓存层)进行统一编排,并完成网络隔离与数据持久化配置,为后续的缓存预热与数据校验提供稳定的运行底座。

4.1 服务架构概览

测试环境由两个核心容器组成:PostgreSQL 负责存储业务主数据,Redis 作为缓存加速层。两者通过自定义桥接网络通信,并各自挂载宿主机目录实现数据持久化,避免容器重启导致数据丢失。

PostgreSQL 与 Redis 容器编排架构 Docker Compose 双容器网络与持久化架构 自定义桥接网络:integration-test-net PostgreSQL 容器 端口: 5432 数据库: testdb 用户: tester Redis 容器 端口: 6379 无密码模式 缓存预热目标 应用层双向通信 宿主机卷: pg_data:/var/lib/postgresql/data 宿主机卷: redis_data:/data

4.2 Docker Compose 文件详解

以下 docker-compose.yml 文件定义了 PostgreSQL 与 Redis 的服务规格、网络模式与持久化卷。所有配置均面向集成测试场景优化,避免生产级安全限制带来的调试复杂性。

version: "3.8"

services:
  postgres:
    image: postgres:15-alpine
    container_name: integration-pg
    restart: unless-stopped
    environment:
      POSTGRES_DB: testdb
      POSTGRES_USER: tester
      POSTGRES_PASSWORD: testpass
    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 testdb"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: integration-redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - integration-test-net
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  pg_data:
    driver: local
  redis_data:
    driver: local

networks:
  integration-test-net:
    driver: bridge

4.3 关键配置项说明

配置项 作用 测试环境注意事项
POSTGRES_DB / USER / PASSWORD 初始化数据库、用户与密码 测试环境使用固定弱密码,便于自动化脚本连接;生产环境禁止此做法
volumes: pg_data 将 PostgreSQL 数据目录挂载到命名卷 容器重启后数据保留;测试前可手动清空卷以重置状态
volumes: ./init-scripts 挂载初始化 SQL 脚本目录 首次启动自动执行建表、索引、测试数据插入脚本
healthcheck 容器健康检查 集成测试启动前应等待 health 状态为 healthy,避免连接失败
networks: integration-test-net 自定义桥接网络 容器间通过服务名(postgres / redis)直接通信,无需依赖宿主机 IP

4.4 网络配置:容器间服务发现

通过自定义网络 integration-test-net,PostgreSQL 与 Redis 容器可以使用服务名称作为主机名进行互访。例如,Python 测试代码中连接 PostgreSQL 时,主机名直接写 postgres 而非 localhost 或 IP 地址。

网络通信示例:

  • PostgreSQL 连接字符串:postgresql://tester:testpass@postgres:5432/testdb
  • Redis 连接字符串:redis://redis:6379/0

这种基于服务名的通信方式,使得容器迁移或扩展时无需修改应用配置。

4.5 持久化卷挂载策略

数据持久化是集成测试环境的重要保障。本方案采用 命名卷(named volumes) 而非绑定挂载(bind mounts),原因如下:

  • 命名卷由 Docker 管理,在宿主机上的实际路径对用户透明,避免跨平台路径兼容性问题。
  • 绑定挂载虽然便于直接查看文件,但在 Windows 与 macOS 上存在文件权限与性能开销。
  • 测试前重置数据时,只需执行 docker compose down -v 即可删除卷并重建。

最佳实践:在 CI/CD 流水线中,每次运行集成测试前建议执行 docker compose down -v && docker compose up -d --wait,确保从干净的数据库与缓存状态开始。

4.6 初始化脚本与数据准备

在 ./init-scripts 目录下放置 SQL 初始化文件,容器首次启动时会按文件名顺序自动执行。以下是一个典型的测试表创建脚本:

-- 01_create_tables.sql
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS orders (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    product_name VARCHAR(200) NOT NULL,
    amount NUMERIC(10,2) NOT NULL,
    status VARCHAR(20) DEFAULT 'pending'
);

-- 插入基础测试数据
INSERT INTO users (username, email) VALUES
    ('test_user_1', 'user1@example.com'),
    ('test_user_2', 'user2@example.com')
ON CONFLICT (username) DO NOTHING;

4.7 启动与验证步骤

完成 docker-compose.yml 与初始化脚本后,按以下步骤启动环境并验证服务可用性:

  1. 启动所有服务:docker compose up -d
  2. 等待健康检查通过:docker compose ps 查看状态,或使用 --wait 参数(Docker Compose v2.20+)
  3. 验证 PostgreSQL:docker exec integration-pg pg_isready -U tester -d testdb
  4. 验证 Redis:docker exec integration-redis redis-cli ping,应返回 PONG
  5. 测试网络互通:docker exec integration-pg ping redis(需容器内安装 ping 工具)

常见问题:如果 PostgreSQL 容器启动后立即退出,请检查 ./init-scripts 目录中的 SQL 文件是否存在语法错误。查看日志命令:docker compose logs postgres。

环境启动与验证流程 环境启动与健康检查流程 docker compose up -d 等待 healthcheck 状态: healthy 验证 PostgreSQL 验证 Redis 环境就绪,可执行测试

4.8 环境清理与重置

集成测试执行完毕后,建议使用以下命令彻底清理环境,避免残留数据影响下一次测试:

# 停止容器并删除卷(数据完全丢失)
docker compose down -v

# 仅停止容器,保留数据(适用于调试后快速重启)
docker compose down

# 重新启动并等待就绪
docker compose up -d --wait

自动化集成建议:在 pytest 的 conftest.py 中,可以使用 subprocess 模块调用 Docker Compose 命令,配合 @pytest.fixture(scope="session") 实现测试会话级别的环境生命周期管理。