feat: 实现门店套餐分配功能并统一测试基础设施
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m30s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m30s
新增功能: - 门店套餐分配管理(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>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -260,6 +260,88 @@ testutils.CleanTestRedisKeys(t, rdb)
|
||||
store := postgres.NewXxxStore(tx, rdb)
|
||||
```
|
||||
|
||||
## 集成测试环境
|
||||
|
||||
对于需要完整 HTTP 请求测试的场景,使用 `IntegrationTestEnv`:
|
||||
|
||||
### 基础用法
|
||||
|
||||
```go
|
||||
func TestAPI_Create(t *testing.T) {
|
||||
env := testutils.NewIntegrationTestEnv(t)
|
||||
|
||||
t.Run("成功创建资源", func(t *testing.T) {
|
||||
reqBody := dto.CreateRequest{
|
||||
Name: fmt.Sprintf("test_%d", time.Now().UnixNano()),
|
||||
}
|
||||
|
||||
jsonBody, _ := json.Marshal(reqBody)
|
||||
resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/resources", jsonBody)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### IntegrationTestEnv API
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| `NewIntegrationTestEnv(t)` | 创建集成测试环境,自动初始化所有依赖 |
|
||||
| `AsSuperAdmin()` | 以超级管理员身份发送请求 |
|
||||
| `AsUser(account)` | 以指定账号身份发送请求 |
|
||||
| `Request(method, path, body)` | 发送 HTTP 请求 |
|
||||
| `CreateTestAccount(...)` | 创建测试账号 |
|
||||
| `CreateTestShop(...)` | 创建测试店铺 |
|
||||
| `CreateTestRole(...)` | 创建测试角色 |
|
||||
| `CreateTestPermission(...)` | 创建测试权限 |
|
||||
|
||||
### 数据隔离最佳实践
|
||||
|
||||
**必须使用动态生成的测试数据**,避免固定值导致的测试冲突:
|
||||
|
||||
```go
|
||||
t.Run("创建资源", func(t *testing.T) {
|
||||
// ✅ 正确:使用动态值
|
||||
name := fmt.Sprintf("test_resource_%d", time.Now().UnixNano())
|
||||
phone := fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000)
|
||||
|
||||
// ❌ 错误:使用固定值(会导致并发测试冲突)
|
||||
name := "test_resource"
|
||||
phone := "13800000001"
|
||||
})
|
||||
```
|
||||
|
||||
### 完整示例
|
||||
|
||||
```go
|
||||
func TestAccountAPI_Create(t *testing.T) {
|
||||
env := testutils.NewIntegrationTestEnv(t)
|
||||
|
||||
t.Run("成功创建平台账号", func(t *testing.T) {
|
||||
username := fmt.Sprintf("platform_user_%d", time.Now().UnixNano())
|
||||
phone := fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000)
|
||||
|
||||
reqBody := dto.CreateAccountRequest{
|
||||
Username: username,
|
||||
Phone: phone,
|
||||
Password: "Password123",
|
||||
UserType: constants.UserTypePlatform,
|
||||
}
|
||||
|
||||
jsonBody, _ := json.Marshal(reqBody)
|
||||
resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/accounts", jsonBody)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
// 验证数据库中账号已创建
|
||||
var count int64
|
||||
env.TX.Model(&model.Account{}).Where("username = ?", username).Count(&count)
|
||||
assert.Equal(t, int64(1), count)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 连接超时
|
||||
@@ -282,3 +364,10 @@ store := postgres.NewXxxStore(tx, rdb)
|
||||
1. 确保使用 `CleanTestRedisKeys`
|
||||
2. 检查是否正确使用 `GetTestRedisKeyPrefix`
|
||||
3. 验证键名是否包含测试名称前缀
|
||||
|
||||
### 测试数据冲突
|
||||
|
||||
如果看到 "用户名已存在" 或 "手机号已存在" 错误:
|
||||
1. 确保使用 `time.Now().UnixNano()` 生成唯一值
|
||||
2. 不要在子测试之间共享固定的测试数据
|
||||
3. 检查是否有遗留的测试数据未被事务回滚
|
||||
|
||||
Reference in New Issue
Block a user