149 lines
4.6 KiB
Markdown
149 lines
4.6 KiB
Markdown
|
|
# 测试数据隔离方案(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 组件,优先在测试层完成隔离与清理。
|