2. 集成测试环境搭建:使用 Docker Compose 编排多服务(Web+DB+Cache)测试环境

在集成测试中,测试环境需要真实地模拟生产部署的拓扑结构。本章将使用 Docker Compose 编排一个包含 Web 应用、PostgreSQL 数据库和 Redis 缓存的典型三服务测试环境,并确保服务间网络互通、启动顺序正确、数据可初始化。

2.1 环境拓扑与组件职责

测试环境由三个核心容器组成,每个容器承担明确的测试角色:

服务名 镜像 端口映射 测试环境职责
web python:3.11-slim 8080:8000 运行 FastAPI 应用,提供 REST 接口供测试脚本调用
db postgres:15-alpine 5432:5432 存储业务数据,测试数据通过初始化脚本注入
cache redis:7-alpine 6379:6379 缓存会话与热点数据,验证缓存穿透/击穿场景
设计原则: 测试环境使用与生产环境相同的镜像版本(alpine 变体),但资源限制更小、日志级别更高,便于调试。
集成测试环境三服务拓扑图 Docker Compose 三服务测试拓扑 test_network (bridge, 172.20.0.0/16) Web 服务 FastAPI / 端口 8000 DB 服务 PostgreSQL 15 / 端口 5432 Cache 服务 Redis 7 / 端口 6379 说明: Web 通过容器名 db:5432 连接 PostgreSQL,通过 cache:6379 连接 Redis。 测试脚本从宿主机 localhost:8080 调用 Web 接口,间接验证 DB 与 Cache。

2.2 Docker Compose 编排文件

在项目根目录创建 docker-compose.yml,定义三个服务、共享网络、数据卷及健康检查:

version: "3.9"

services:
  db:
    image: postgres:15-alpine
    container_name: test-db
    environment:
      POSTGRES_USER: testuser
      POSTGRES_PASSWORD: testpass
      POSTGRES_DB: testdb
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init-scripts:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U testuser -d testdb"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - test_network

  cache:
    image: redis:7-alpine
    container_name: test-cache
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - test_network

  web:
    build:
      context: ./app
      dockerfile: Dockerfile.test
    container_name: test-web
    ports:
      - "8080:8000"
    environment:
      DATABASE_URL: postgresql://testuser:testpass@db:5432/testdb
      REDIS_URL: redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_healthy
    volumes:
      - ./app:/app
    networks:
      - test_network

volumes:
  pgdata:

networks:
  test_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16
关键配置解读:
• depends_on 配合 condition: service_healthy 确保 Web 在 DB 和 Cache 就绪后才启动。
• 使用 healthcheck 替代简单的 sleep,避免竞态条件。
• 显式指定 subnet 便于测试脚本固定 IP 白名单。

2.3 数据库初始化脚本

在 init-scripts/ 目录下创建 01-init.sql,注入测试所需的表结构和种子数据:

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

INSERT INTO users (username, email) VALUES
    ('test_user_1', 'test1@example.com'),
    ('test_user_2', 'test2@example.com'),
    ('admin', 'admin@example.com')
ON CONFLICT (username) DO NOTHING;

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

INSERT INTO orders (user_id, amount, status) VALUES
    (1, 99.99, 'completed'),
    (1, 150.00, 'pending'),
    (2, 45.50, 'completed');

2.4 启动与验证步骤

  1. 启动环境: docker compose up -d --build
  2. 检查服务状态: docker compose ps 确认三个容器均为 Up (healthy)
  3. 验证网络连通: docker compose exec web ping -c 2 db
  4. 验证数据库初始化: docker compose exec db psql -U testuser -d testdb -c "SELECT * FROM users;"
  5. 验证缓存可用: docker compose exec cache redis-cli ping 应返回 PONG
常见问题:
• 端口冲突:宿主机 5432/6379 已被占用时,修改 ports 映射为宿主机其他端口(如 15432:5432)。
• 初始化脚本未执行:检查 volumes 挂载路径是否正确,PostgreSQL 仅首次启动时执行 init 目录下的脚本。
• 健康检查超时:若容器启动较慢,适当增加 interval 和 retries 参数。

2.5 环境清理与数据持久化

测试结束后,使用以下命令清理环境:

# 停止并移除容器、网络
docker compose down

# 同时删除数据卷(谨慎:会丢失所有测试数据)
docker compose down -v

# 仅重启服务(保留数据卷)
docker compose restart
命令 容器 网络 数据卷 适用场景
docker compose down 删除 删除 保留 日常测试迭代,保留数据加速下次启动
docker compose down -v 删除 删除 删除 CI/CD 流水线,确保每次从干净状态开始
docker compose restart 重启 保留 保留 修改配置后快速生效
Docker Compose 启动与健康检查时序图 服务启动顺序与健康检查流程 时间 docker compose up DB 启动 pg_isready 轮询 Cache 启动 redis-cli ping 轮询 Web 启动 依赖就绪后启动 健康检查依赖链: 1. DB 和 Cache 并行启动,各自执行健康检查命令。 2. 仅当两个依赖服务均为 healthy 状态时,Compose 才启动 Web 服务。 3. Web 启动后,测试脚本可通过 localhost:8080 访问,无需额外等待。

2.6 集成测试环境验证清单

环境搭建完成后,执行以下快速验证,确保所有组件正常工作:

  • Web 接口可达: curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health 应返回 200
  • 数据库读写: 调用 POST /api/users 创建用户,再 GET /api/users/1 验证数据持久化
  • 缓存命中: 连续两次请求同一接口,第二次响应时间应显著降低(X-Cache: HIT 头)
  • 日志输出: docker compose logs web 应显示应用启动日志,无数据库连接错误
自动化集成: 将上述验证步骤写入 Makefile 或 scripts/verify_env.sh,在 CI 流水线中作为前置检查步骤,确保测试环境始终可用。