## Context ### 当前状态 项目存在三种不同的测试基础设施方式: | 方式 | 使用文件 | 问题 | |------|---------|------| | **testcontainers** | `role_test.go` | 需要 Docker,启动慢(30s+/测试),CI 环境复杂 | | **共享数据库 + DELETE** | `shop_management_test.go` 等 | 清理不可靠,数据残留,并行冲突 | | **事务隔离** | 部分单元测试 | ✅ 正确方式,已有 `testutils.NewTestTransaction` | ### 现有基础设施 `tests/testutils/db.go` 已提供: - `GetTestDB(t)` - 全局单例数据库连接 - `NewTestTransaction(t)` - 创建自动回滚的测试事务 - `GetTestRedis(t)` - 全局单例 Redis 连接 - `CleanTestRedisKeys(t, rdb)` - 自动清理测试 Redis 键 问题是**集成测试没有使用这些工具**,而是各自实现了不同的方式。 ## Goals / Non-Goals **Goals:** - 统一所有集成测试使用事务隔离模式 - 移除 testcontainers 依赖,简化测试环境要求 - 消除 DELETE 清理代码,改用事务自动回滚 - 提供标准化的集成测试环境设置模式 - 确保测试可以并行运行且互不干扰 **Non-Goals:** - 不改变测试的业务逻辑验证内容 - 不引入新的测试框架或依赖 - 不修改 `testutils` 的核心 API(仅增强) - 不处理性能测试或压力测试场景 ## Decisions ### 决策 1:统一使用事务隔离模式 **选择**: 所有集成测试使用 `testutils.NewTestTransaction(t)` 获取独立事务 **理由**: - 已有成熟实现,无需重新开发 - 事务回滚比 DELETE 快 100 倍以上 - 完全隔离,支持并行执行 - 不需要 Docker,降低环境要求 **放弃的替代方案**: - testcontainers:启动慢、需要 Docker、CI 配置复杂 - 共享数据库 + 命名前缀:清理不可靠、并行时冲突 ### 决策 2:增强 testutils 支持集成测试 **选择**: 在 `testutils` 包中添加集成测试专用的辅助函数 新增函数: ```go // NewIntegrationTestEnv 创建集成测试环境 // 包含:事务、Redis、Logger、TokenManager、App func NewIntegrationTestEnv(t *testing.T) *IntegrationTestEnv // IntegrationTestEnv 集成测试环境 type IntegrationTestEnv struct { TX *gorm.DB // 自动回滚的事务 Redis *redis.Client // 全局 Redis 连接 Logger *zap.Logger // 测试用 Logger TokenManager *auth.TokenManager App *fiber.App // 配置好的 Fiber App } ``` **理由**: - 减少每个测试文件的重复代码 - 统一 ErrorHandler、中间件配置 - 方便后续扩展 ### 决策 3:测试数据生成策略 **选择**: 使用原子计数器 + 时间戳生成唯一标识 ```go // 已有实现,继续使用 testutils.GenerateUniquePhone() // 138 + 时间戳后8位 testutil.GenerateUniqueUsername(prefix) // prefix_counter ``` **理由**: - 即使并行运行也不会冲突 - 不依赖随机数(可重现) - 已有实现,经过验证 ### 决策 4:Fiber App 配置统一 **选择**: 在 `IntegrationTestEnv` 中预配置标准的 Fiber App 配置内容: - `ErrorHandler`: 使用 `errors.SafeErrorHandler` - 中间件: 认证中间件(模拟用户上下文) - 路由: 使用 `routes.RegisterRoutes` 注册 **理由**: - 与生产环境配置一致 - 避免每个测试文件重复配置 - 便于测试真实的错误处理逻辑 ## Risks / Trade-offs ### 风险 1:重构范围大 **风险**: 涉及 15-20 个测试文件,可能引入新 bug **缓解**: - 逐个文件重构,每个文件重构后立即验证 - 保留原有测试用例逻辑,只改变环境设置方式 - 使用 `git diff` 确保只改变了预期的部分 ### 风险 2:事务隔离的限制 **风险**: 某些测试可能需要真实的数据库提交(如测试并发) **缓解**: - 这类测试极少,可以特殊处理 - 文档说明何时需要跳过事务隔离 ### 风险 3:testcontainers 测试可能测试了特定功能 **风险**: testcontainers 测试可能依赖完整的数据库生命周期 **缓解**: - 分析每个 testcontainers 测试的实际需求 - 大多数只需要隔离的数据库环境,事务可以满足 ## Migration Plan ### 阶段 1:增强 testutils(1-2 小时) 1. 添加 `IntegrationTestEnv` 结构和 `NewIntegrationTestEnv` 函数 2. 添加常用的测试辅助函数(创建测试用户、生成 Token 等) 3. 编写使用文档 ### 阶段 2:重构 testcontainers 测试(2-3 小时) 1. 重构 `role_test.go` 2. 移除 testcontainers 导入 3. 验证所有测试通过 ### 阶段 3:重构 DELETE 清理测试(3-4 小时) 1. 重构 `shop_management_test.go` 2. 重构 `shop_account_management_test.go` 3. 重构其他使用 DELETE 清理的测试 4. 删除所有 `teardown` 中的 DELETE 语句 ### 阶段 4:清理和验证(1 小时) 1. 移除 `go.mod` 中的 testcontainers 依赖 2. 运行全量测试验证 3. 更新测试文档 ### 回滚策略 - 每个阶段完成后提交 - 如果某个阶段失败,可以 revert 到上一个阶段 - 保留原测试文件的 git 历史,方便对比 ## Open Questions 1. **是否需要保留某些 testcontainers 测试?** - 初步判断:不需要,所有测试都可以用事务隔离替代 - 需要在实施时验证 2. **并发测试如何处理?** - 当前项目没有并发测试 - 如果未来需要,可以单独处理 3. **测试数据库的 AutoMigrate 策略?** - 当前在 `GetTestDB` 首次调用时执行 - 可能需要扩展迁移的模型列表