Files
social-app/docs/plans/PLAN-test-db-isolation-2026-02-05.md
T

149 lines
4.6 KiB
Markdown
Raw Normal View History

# 测试数据隔离方案(Supabase + Python 后端)
## 背景现状
- 后端在 `backend/src/core/config/settings.py` 使用 `SOCIAL_DATABASE__*` 生成 `database_url`
- 本地 Supabase 通过 `supabase-db` 容器提供 Postgres,宿主端口由 `SOCIAL_DATABASE__PORT` 控制(默认映射到容器 5432)。
- 注意:`supabase-pooler` 的 5432 仅用于连接池;测试与迁移应直连 `supabase-db` 的宿主端口。
- 单元数据库测试目前使用 SQLite 内存库(见 `tests/unit/database/*`),不影响开发库。
- 真实 Postgres 的集成/E2E 当前未统一隔离策略;当开始接入真实 DB 时,需要按本文方案隔离与清理。
## 目标
- 测试过程不污染开发数据。
- 测试可重复、可并行、可在本地与 CI 稳定运行。
- 变更成本可控,优先在现有架构上落地。
## 结论(适配本项目)
采用“事务回滚 + 独立测试数据库”的混合策略:
- 默认测试使用事务回滚,快速、零污染(适用于单连接/单事务场景)。
- 需要真实提交、并发或触发器行为的测试使用独立测试数据库。
## 方案设计
### A. 事务回滚(默认)
适用:单元测试、绝大多数集成测试(当这些测试连接真实 Postgres 时)。
核心思路:
- 每个测试在事务中运行。
- 测试结束自动回滚。
优点:
- 速度快,无需新增数据库。
- 测试间完全隔离。
限制:
- 无法验证真实 COMMIT 结果。
- 并发、多连接事务隔离测试不准确。
### B. 独立测试数据库(E2E/并发)
适用:E2E、并发、触发器、LISTEN/NOTIFY 等需要真实提交的场景。
核心思路:
- 在现有 Supabase Postgres 实例中创建独立数据库。
- 测试使用专用 `SOCIAL_DATABASE__NAME` 连接,端口/账号/密码来自 `SOCIAL_DATABASE__*`
- 测试前应用迁移,测试后清理。
优点:
- 行为最接近真实环境。
- 与开发数据完全隔离。
成本:
- 需要迁移与清理策略。
## 与现有测试模块的衔接
- `tests/unit/database/*` 已使用 SQLite 内存库,无需改造。
- 未来若 `tests/integration/*``tests/e2e/*` 连接真实 Postgres,应切换到本文的测试库策略。
- 使用 `SOCIAL_DATABASE__NAME=postgres_test` 启动测试,以避免污染开发库。
## 实施步骤(与项目当前结构对齐)
### 1) 创建独立测试数据库
在本地 Supabase 容器中创建测试库:
```bash
docker exec -e PGPASSWORD="$SOCIAL_DATABASE__PASSWORD" supabase-db \
psql -U "$SOCIAL_DATABASE__USER" -c "CREATE DATABASE postgres_test;"
```
说明:
- 容器名为 `supabase-db`(已在 `infra/docker` 运行)。
- 数据库名建议 `postgres_test`,与 `.env``SOCIAL_DATABASE__NAME=postgres` 区分。
### 2) 运行迁移到测试库
使用测试环境变量指向测试库后,应用 Alembic 迁移:
```bash
SOCIAL_RUNTIME__ENVIRONMENT=test \
SOCIAL_DATABASE__NAME=postgres_test \
uv run alembic upgrade head
```
说明:
- 执行位置:`/home/qzl/Code/social-app/backend`
- 仍使用当前 `.env` 中的 `SOCIAL_DATABASE__HOST``SOCIAL_DATABASE__PORT`
### 3) 事务回滚测试(默认)
测试执行时注入事务回滚机制:
- 在测试会话层创建单连接事务。
- 对每个测试用例使用 SAVEPOINT(或嵌套事务)。
- 测试结束回滚到 SAVEPOINT。
这套策略可保持速度与隔离性,同时不需要额外数据库。
### 4) 独立测试数据库执行(E2E/并发)
对于需要真实提交的测试,使用测试库运行:
```bash
SOCIAL_RUNTIME__ENVIRONMENT=test \
SOCIAL_DATABASE__NAME=postgres_test \
uv run pytest tests/e2e
```
清理策略(二选一):
- 小规模测试:TRUNCATE public schema 的业务表(不影响 `auth` 等系统 schema)。
- 大规模测试:`DROP DATABASE postgres_test;` 后重建并迁移。
### 5) 本地/CI 统一策略
- 本地默认:事务回滚。
- CI:独立测试库(保证完全隔离、无隐式依赖)。
## 风险与规避
- 不要在清理时操作 `auth``storage` 等 Supabase 系统 schema。
- E2E 使用独立数据库,避免与开发数据交叉。
- 迁移必须由 Alembic 统一维护,禁止手动改库。
## 落地检查清单
- [ ] 已创建 `postgres_test` 数据库。
- [ ] 测试库迁移已应用。
- [ ] 事务回滚测试已接入(默认路径)。
- [ ] E2E 使用测试库运行。
- [ ] 清理策略执行脚本可复用。
## 备注
本方案基于当前项目的 Supabase 本地 Docker 结构与后端配置方式(`SOCIAL_DATABASE__*`)。
无需变更 Supabase 组件,优先在测试层完成隔离与清理。