2. 环境准备:Docker部署PostgreSQL、安装pgTAP扩展、配置测试数据库与用户权限

本章是实战案例的基础设施搭建环节。我们将通过 Docker 快速拉起 PostgreSQL 实例,安装 pgTAP 单元测试扩展,并完成测试数据库与用户权限的精细化配置。所有后续章节的 Mock 隔离场景均依赖此环境。

2.1 整体架构概览

下图展示了本次环境准备的核心组件与交互关系:Docker 容器承载 PostgreSQL 实例,内部集成 pgTAP 扩展,外部通过端口映射暴露服务,测试脚本通过专用用户连接测试数据库执行单元测试。

环境准备架构图 环境准备架构图 Docker 主机 PostgreSQL 容器 PostgreSQL 16 核心进程 pgTAP 扩展 (v1.2.1) 测试数据库 (unittest_db) 外部客户端 / 测试脚本 psql / pg_prove CI/CD 流水线 开发者本地环境 端口 5432 端口映射: 5432 → 5432 用户: tester / 密码: testpass

2.2 Docker 部署 PostgreSQL

使用官方 PostgreSQL 16 镜像,通过 Docker Compose 实现可重复的环境部署。以下为 docker-compose.yml 配置:

version: '3.8'

services:
  postgres:
    image: postgres:16
    container_name: pg_mock_lab
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - pg_data:/var/lib/postgresql/data
      - ./init-scripts:/docker-entrypoint-initdb.d
    networks:
      - pg_net

volumes:
  pg_data:

networks:
  pg_net:
    driver: bridge
提示: 将初始化脚本(含 pgTAP 安装与数据库创建)放入 ./init-scripts 目录,容器首次启动时会自动按文件名顺序执行。

2.3 安装 pgTAP 扩展

pgTAP 是 PostgreSQL 的单元测试框架,提供丰富的断言函数。安装方式有两种:

安装方式 命令 / 步骤 适用场景
APT 包管理器 apt-get install postgresql-16-pgtap Debian/Ubuntu 系统,快速安装
源码编译 make && make install 自定义 PostgreSQL 编译环境
Docker 初始化脚本 在 init-scripts 中执行 CREATE EXTENSION pgtap; 容器化部署,推荐方式

在 Docker 环境中,我们通过初始化脚本自动安装。创建 init-scripts/01-install-pgtap.sh:

#!/bin/bash
set -e

# 安装 pgTAP 扩展包
apt-get update
apt-get install -y postgresql-16-pgtap

# 连接到默认数据库并创建扩展
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
    CREATE EXTENSION IF NOT EXISTS pgtap;
    SELECT * FROM pg_extension WHERE extname = 'pgtap';
EOSQL

echo "pgTAP 扩展安装完成"
注意: 确保脚本具有可执行权限(chmod +x),否则 Docker 不会执行。安装完成后可通过 \dx 命令验证扩展列表。

2.4 配置测试数据库与用户权限

为隔离测试环境,创建专用数据库和低权限用户。创建 init-scripts/02-create-test-db.sh:

#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
    -- 创建测试数据库
    CREATE DATABASE unittest_db
        WITH ENCODING 'UTF8'
        LC_COLLATE = 'en_US.utf8'
        LC_CTYPE = 'en_US.utf8'
        TEMPLATE template0;

    -- 创建测试用户(仅授予最小权限)
    CREATE USER tester WITH PASSWORD 'testpass';
    GRANT CONNECT ON DATABASE unittest_db TO tester;
    GRANT USAGE ON SCHEMA public TO tester;
    GRANT CREATE ON SCHEMA public TO tester;
    GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO tester;
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO tester;

    -- 在测试数据库中安装 pgTAP
    \c unittest_db
    CREATE EXTENSION IF NOT EXISTS pgtap;

    -- 验证安装
    SELECT 'pgTAP installed successfully' AS status;
EOSQL

echo "测试数据库与用户配置完成"

2.5 权限矩阵与安全隔离

下表展示了不同用户在不同数据库上的权限差异,体现 Mock 测试所需的权限最小化原则:

用户 数据库 连接 读表 写表 创建对象 超级用户
postgres 所有 ✓ ✓ ✓ ✓ ✓
tester unittest_db ✓ ✓ ✓ ✓ ✗
tester postgres ✗ ✗ ✗ ✗ ✗

2.6 验证环境

启动容器后,执行以下命令验证环境是否就绪:

# 启动容器
docker-compose up -d

# 验证 PostgreSQL 运行状态
docker exec pg_mock_lab pg_isready -U postgres

# 验证 pgTAP 扩展
docker exec pg_mock_lab psql -U postgres -d unittest_db -c "SELECT * FROM pg_extension WHERE extname = 'pgtap';"

# 验证用户连接
docker exec pg_mock_lab psql -U tester -d unittest_db -c "SELECT current_user, current_database();"

# 运行 pgTAP 自检
docker exec pg_mock_lab psql -U tester -d unittest_db -c "SELECT plan(1); SELECT pass('Environment is ready'); SELECT * FROM finish();"
预期输出: 最后一条命令应返回类似 1..1\nok 1 - Environment is ready 的结果,表示 pgTAP 工作正常。

2.7 环境配置清单

完成本章配置后,应获得以下环境要素:

  • PostgreSQL 16 — 运行在 Docker 容器中,端口 5432 映射到宿主机
  • pgTAP 扩展 v1.2.1 — 安装在 unittest_db 数据库中
  • 测试数据库 unittest_db — 专用测试空间,与生产数据库隔离
  • 测试用户 tester — 仅拥有 unittest_db 的完整权限,无超级用户权限
  • 初始化脚本 — 位于 init-scripts/ 目录,支持一键重建环境
环境验证流程 环境验证流程 docker-compose up -d pg_isready 检查 扩展验证 用户连接测试 pgTAP 自检 全部通过后,环境准备完成,可进入 Mock 依赖隔离场景实战

2.8 常见问题与排错

  • pgTAP 扩展创建失败: 检查是否已安装 postgresql-16-pgtap 包,或手动执行 CREATE EXTENSION pgtap; 时是否在正确的数据库中。
  • 用户连接被拒绝: 确认 pg_hba.conf 中允许 tester 用户通过 md5 认证方式连接 unittest_db。
  • 初始化脚本未执行: 检查脚本是否具有可执行权限,文件名是否以 .sh 结尾,Docker 日志中是否有错误信息。
  • 端口冲突: 如果宿主机 5432 已被占用,修改 docker-compose.yml 中的端口映射,例如 "5433:5432"。
最佳实践: 将 docker-compose.yml 和 init-scripts/ 目录纳入版本控制,团队成员可一键复现完全一致的测试环境。