Files
junhong_cmp_fiber/openspec/changes/unify-test-infrastructure/design.md
huang 23eb0307bb
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m30s
feat: 实现门店套餐分配功能并统一测试基础设施
新增功能:
- 门店套餐分配管理(shop_package_allocation):支持门店套餐库存管理
- 门店套餐系列分配管理(shop_series_allocation):支持套餐系列分配和佣金层级设置
- 我的套餐查询(my_package):支持门店查询自己的套餐分配情况

测试改进:
- 统一集成测试基础设施,新增 testutils.NewIntegrationTestEnv
- 重构所有集成测试使用新的测试环境设置
- 移除旧的测试辅助函数和冗余测试文件
- 新增 test_helpers_test.go 统一任务测试辅助

技术细节:
- 新增数据库迁移 000025_create_shop_allocation_tables
- 新增 3 个 Handler、Service、Store 和对应的单元测试
- 更新 OpenAPI 文档和文档生成器
- 测试覆盖率:Service 层 > 90%

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-28 10:45:16 +08:00

5.4 KiB
Raw Blame History

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 包中添加集成测试专用的辅助函数

新增函数:

// 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测试数据生成策略

选择: 使用原子计数器 + 时间戳生成唯一标识

// 已有实现,继续使用
testutils.GenerateUniquePhone()  // 138 + 时间戳后8位
testutil.GenerateUniqueUsername(prefix) // prefix_counter

理由:

  • 即使并行运行也不会冲突
  • 不依赖随机数(可重现)
  • 已有实现,经过验证

决策 4Fiber App 配置统一

选择: 在 IntegrationTestEnv 中预配置标准的 Fiber App

配置内容:

  • ErrorHandler: 使用 errors.SafeErrorHandler
  • 中间件: 认证中间件(模拟用户上下文)
  • 路由: 使用 routes.RegisterRoutes 注册

理由:

  • 与生产环境配置一致
  • 避免每个测试文件重复配置
  • 便于测试真实的错误处理逻辑

Risks / Trade-offs

风险 1重构范围大

风险: 涉及 15-20 个测试文件,可能引入新 bug 缓解:

  • 逐个文件重构,每个文件重构后立即验证
  • 保留原有测试用例逻辑,只改变环境设置方式
  • 使用 git diff 确保只改变了预期的部分

风险 2事务隔离的限制

风险: 某些测试可能需要真实的数据库提交(如测试并发) 缓解:

  • 这类测试极少,可以特殊处理
  • 文档说明何时需要跳过事务隔离

风险 3testcontainers 测试可能测试了特定功能

风险: testcontainers 测试可能依赖完整的数据库生命周期 缓解:

  • 分析每个 testcontainers 测试的实际需求
  • 大多数只需要隔离的数据库环境,事务可以满足

Migration Plan

阶段 1增强 testutils1-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 首次调用时执行
    • 可能需要扩展迁移的模型列表