diff --git a/supply-api/CLAUDE.md b/supply-api/CLAUDE.md new file mode 100644 index 00000000..b228429f --- /dev/null +++ b/supply-api/CLAUDE.md @@ -0,0 +1,378 @@ +# Supply API - Claude Code 项目规范 + +## 项目概述 + +Supply API 是一个基于 Go 的微服务,提供供应链管理功能,包括账户管理、套餐管理、结算服务、收益服务和审计日志。 + +## 技术栈 + +- **语言**: Go 1.21+ +- **数据库**: PostgreSQL 15+ +- **缓存**: Redis +- **框架**: 标准库 + 自定义中间件 +- **测试**: Go testing + testify + +--- + +## 代码规范 + +### 1. 命名规范 + +#### 1.1 字段命名统一 +**关键经验**: 跨模块字段必须保持命名一致,否则会导致类型转换错误。 + +| 规范 | 示例 | 说明 | +|------|------|------| +| IP来源字段 | `SourceIP` | 统一使用 `SourceIP`,禁止使用 `ClientIP` | +| 追踪ID字段 | `TraceID` | W3C Trace Context 标准 | +| 请求ID字段 | `RequestID` | HTTP 请求追踪 | +| 幂等键字段 | `IdempotencyKey` | 统一命名 | + +#### 1.2 结构体命名 +``` +// ✅ 正确 +type AuditEvent struct { + SourceIP string `json:"source_ip"` +} + +// ❌ 错误 - 与其他模块不一致 +type AuditEvent struct { + ClientIP string `json:"client_ip"` +} +``` + +### 2. 接口设计 + +#### 2.1 Store 接口必须包含版本控制 +**关键经验**: 乐观锁是防止并发更新导致数据不一致的标准做法。 + +```go +// ✅ 正确 - 包含 expectedVersion 参数 +type SettlementStore interface { + Update(ctx context.Context, s *Settlement, expectedVersion int) error +} + +// ❌ 错误 - 缺少版本控制 +type SettlementStore interface { + Update(ctx context.Context, s *Settlement) error +} +``` + +#### 2.2 领域服务接口与实现分离 +```go +// 领域层定义接口 +type SettlementStore interface { + Create(ctx context.Context, s *Settlement) error + GetByID(ctx context.Context, supplierID, id int64) (*Settlement, error) + Update(ctx context.Context, s *Settlement, expectedVersion int) error + List(ctx context.Context, supplierID int64) ([]*Settlement, error) + GetWithdrawableBalance(ctx context.Context, supplierID int64) (float64, error) +} +``` + +### 3. 中间件设计 + +#### 3.1 Logging 中间件必须使用结构化日志 +**关键经验**: 标准库 `log` 无法满足生产环境可观测性需求。 + +```go +// ✅ 正确 - 使用结构化日志接口 +func Logging(next http.Handler, logger logging.Logger) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fields := map[string]interface{}{ + "method": r.Method, + "path": r.URL.Path, + } + logger.Info("HTTP request", fields) + next.ServeHTTP(w, r) + }) +} +``` + +#### 3.2 Tracing 中间件解析 W3C Trace Context +```go +// W3C Trace Context 标准 traceparent header 格式 +// traceparent: 00-{trace-id}-{span-id}-{trace-flags} +func ParseTraceParent(traceParent string) (*TraceContext, error) { + // 格式: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01 + // 长度: 55 字符 +} +``` + +### 4. 健康检查设计 + +#### 4.1 统一使用 HealthHandler +**关键经验**: 避免重复实现导致的维护负担和不一致。 + +```go +// ✅ 正确 - 使用统一的 HealthHandler +healthHandler := httpapi.NewHealthHandlerWithDefaults(dbHealthCheck, redisHealthCheck) +mux.HandleFunc("/actuator/health", healthHandler.ServeHealth) + +// ❌ 错误 - inline handler 导致代码重复 +mux.HandleFunc("/actuator/health", handleHealthCheck(db, redisCache)) +``` + +#### 4.2 健康检查端点路径 +| 路径 | 说明 | +|------|------| +| `/actuator/health` | 综合健康检查 | +| `/actuator/health/live` | 存活探针 | +| `/actuator/health/ready` | 就绪探针 | + +### 5. 审计日志设计 + +#### 5.1 事件字段规范 +```go +type Event struct { + EventID string `json:"event_id,omitempty"` + TenantID int64 `json:"tenant_id"` + ObjectType string `json:"object_type"` // e.g., "supply_settlement" + ObjectID int64 `json:"object_id"` + Action string `json:"action"` // e.g., "withdraw", "cancel" + BeforeState map[string]any `json:"before_state,omitempty"` + AfterState map[string]any `json:"after_state,omitempty"` + RequestID string `json:"request_id,omitempty"` + ResultCode string `json:"result_code"` // e.g., "OK", "SUP_SET_4001" + SourceIP string `json:"source_ip,omitempty"` + CreatedAt time.Time `json:"created_at"` +} +``` + +#### 5.2 敏感信息脱敏 +审计日志必须脱敏处理: +- 手机号、邮箱 +- 身份证号 +- 银行账号 +- 密码和密钥 + +### 6. 错误处理 + +#### 6.1 错误码格式 +``` +{SOURCE}_{CATEGORY}_{CODE} +例如: SUP_SET_4001 +- SUP: 来源系统 +- SET: 业务类别 (settlement) +- 4001: 具体错误码 +``` + +#### 6.2 错误信息不泄露内部细节 +```go +// ✅ 正确 - 用户友好错误信息 +return errors.New("SUP_SET_4001: withdraw amount exceeds available balance") + +// ❌ 错误 - 泄露内部实现 +return errors.New("database connection failed: connection refused") +``` + +### 7. 数据库设计 + +#### 7.1 乐观锁实现 +```sql +-- PostgreSQL 乐观锁 +UPDATE settlements +SET status = $1, version = version + 1, updated_at = NOW() +WHERE id = $2 AND version = $3 +RETURNING id; +-- 如果返回 0 行,说明版本冲突 +``` + +#### 7.2 悲观锁实现 +```sql +-- 扣减配额时使用悲观锁 +UPDATE supply_packages +SET available_quota = available_quota - $1, + sold_quota = sold_quota + $1 +WHERE id = $2 AND user_id = $3 AND available_quota >= $1 +RETURNING id; +``` + +--- + +## 测试规范 + +### 1. 测试文件命名 +``` +{package}_test.go // 标准测试(默认) +{package}_integration_test.go // 集成测试(需数据库) +{package}_e2e_test.go // 端到端测试 +``` + +### 2. Mock 接口而非具体实现 +```go +// ✅ 正确 - Mock 接口 +type mockSettlementStore struct { + settlements map[int64]*Settlement +} + +func (m *mockSettlementStore) GetByID(ctx context.Context, supplierID, id int64) (*Settlement, error) { + if s, ok := m.settlements[id]; ok && s.SupplierID == supplierID { + return s, nil + } + return nil, errors.New("not found") +} + +// ❌ 错误 - Mock 具体类型 +type mockRepo struct { + repo *repository.SettlementRepository +} +``` + +### 3. Mock 审计存储签名(关键) +审计存储接口方法签名为: +```go +type AuditStore interface { + Emit(ctx context.Context, event audit.Event) error // 注意是 audit.Event 不是 interface{} + Query(ctx context.Context, filter audit.EventFilter) ([]audit.Event, error) + QueryWithTotal(ctx context.Context, filter audit.EventFilter) ([]audit.Event, int64, error) + GetByID(ctx context.Context, eventID string) (audit.Event, error) +} +``` + +### 4. 测试覆盖率要求 +| 模块 | 最低覆盖率 | 说明 | +|------|-----------|------| +| domain | 70% | 领域模型、状态机、业务规则 | +| audit/service | 80% | 审计服务、告警服务 | +| audit/handler | 75% | HTTP 处理器 | +| audit/model | 80% | 数据模型、验证 | +| audit/sanitizer | 80% | 敏感信息脱敏 | +| middleware | 80% | 认证、限流、幂等 | +| security | 80% | 安全相关 | +| iam | 70% | 身份认证授权 | + +### 5. 测试运行命令 +```bash +# 快速测试(跳过集成测试) +go test -short ./... + +# 包含集成测试 +go test -tags=integration ./... + +# 详细输出 +go test -v -cover ./internal/domain/... + +# 检查覆盖率 +go test -cover ./... +``` + +### 6. 测试命名规范 +``` +Test{Service}_{Method}_{Scenario} + +示例: +- TestAccountService_Create_Success +- TestAccountService_Create_InvalidInput +- TestPackageService_Publish_ExpiredPackage +- TestSettlementService_Withdraw_ExceedsBalance +``` + +--- + +## Git 提交规范 + +### 1. 提交信息格式 +``` +{type}: {subject} + +{body} + +{footer} +``` + +### 2. Type 类型 +- `fix`: 缺陷修复 +- `feat`: 新功能 +- `docs`: 文档更新 +- `refactor`: 重构 +- `test`: 测试相关 +- `chore`: 构建/工具变更 + +### 3. 示例 +``` +fix: 修复结算更新时的乐观锁冲突 + +问题:并发更新结算状态时可能导致数据覆盖 +解决:添加 expectedVersion 参数实现乐观锁 + +Fixes: SUP-1234 +``` + +--- + +## 依赖管理 + +### 1. 使用 Go Modules +```bash +go mod init lijiaoqiao/supply-api +go mod tidy +``` + +### 2. 禁止依赖未验证的包 +评估标准: +- 维护状态 +- 下载量 +- 安全漏洞历史 + +--- + +## 配置管理 + +### 1. 环境配置分离 +``` +config/ +├── config.dev.yaml +├── config.staging.yaml +└── config.prod.yaml +``` + +### 2. 敏感配置通过环境变量 +```yaml +database: + password: ${DB_PASSWORD} +``` + +--- + +## 常见问题与解决方案 + +### Q1: 如何处理跨模块命名不一致? +**A**: 建立字段命名标准文档,所有模块遵循 W3C 和行业通用命名。 + +### Q2: 何时使用乐观锁 vs 悲观锁? +**A**: +- 乐观锁:读多写少,低冲突场景 +- 悲观锁:高并发写,财务类敏感操作 + +### Q3: 如何避免中间件代码重复? +**A**: 使用统一的 Handler 模式,集中管理公共逻辑。 + +### Q4: 审计日志的性能影响如何控制? +**A**: 采样策略 + 异步写入 + 批量处理。 + +--- + +## 文件结构 + +``` +supply-api/ +├── cmd/supply-api/ # 主程序入口 +├── internal/ +│ ├── audit/ # 审计日志模块 +│ │ ├── model/ # 审计事件模型 +│ │ ├── service/ # 审计服务 +│ │ ├── handler/ # HTTP 处理器 +│ │ ├── repository/ # 数据库仓储 +│ │ ├── sanitizer/ # 敏感信息脱敏 +│ │ └── events/ # 事件定义 +│ ├── iam/ # IAM 模块 +│ ├── domain/ # 领域模型 +│ ├── middleware/ # HTTP 中间件 +│ ├── repository/ # 通用数据仓储 +│ ├── cache/ # Redis 缓存 +│ ├── config/ # 配置管理 +│ └── pkg/ # 公共包 +├── sql/postgresql/ # 数据库 DDL 脚本 +└── docs/ # 设计文档 +``` diff --git a/supply-api/docs/testing_strategy_v1.md b/supply-api/docs/testing_strategy_v1.md new file mode 100644 index 00000000..5ff433cf --- /dev/null +++ b/supply-api/docs/testing_strategy_v1.md @@ -0,0 +1,450 @@ +# Supply API 测试方案 v1.0 + +## 1. 概述 + +本文档定义了 Supply API 项目的系统性测试策略,确保代码质量、可维护性和快速迭代能力。 + +### 1.1 测试金字塔 + +``` + ┌─────────────┐ + │ E2E │ ← 少量关键路径验证 + ┌─────────────┐ + │ Integration│ ← API、DB、消息队列集成 + ┌───────────────┐ + │ Unit │ ← 大量快速反馈 + ┌─────────────────┐ + │ Component │ ← 单组件内部逻辑 + ┌───────────────────┐ +``` + +### 1.2 测试类型定义 + +| 类型 | 目标 | 工具 | 速度 | +|------|------|------|------| +| 单元测试 | 业务逻辑、领域模型 | Go testing + testify | < 1ms | +| 集成测试 | Store、Repository、DB | go:build integration | < 100ms | +| E2E测试 | 关键业务流程 | Playwright | < 1s | + +--- + +## 2. 测试组织结构 + +### 2.1 文件命名规范 + +``` +{package}_test.go // 单元测试(默认) +{package}_integration_test.go // 集成测试(需数据库) +{package}_e2e_test.go // 端到端测试 +``` + +### 2.2 测试包结构 + +``` +internal/ +├── domain/ # 领域模型 +│ ├── account.go # 账号领域逻辑 +│ ├── account_test.go # 账号单元测试 +│ ├── package.go # 套餐领域逻辑 +│ ├── package_test.go # 套餐单元测试 +│ └── invariants_test.go # 不变量测试 +│ +├── audit/ # 审计模块 +│ ├── service/ +│ │ ├── audit_service.go +│ │ └── audit_service_test.go +│ └── handler/ +│ ├── audit_handler.go +│ └── audit_handler_test.go +│ +├── middleware/ # HTTP中间件 +│ ├── auth.go +│ ├── auth_test.go # 认证测试 +│ ├── ratelimit.go +│ └── ratelimit_test.go # 限流测试 +``` + +--- + +## 3. 单元测试规范 + +### 3.1 测试结构 (AAA模式) + +```go +func TestXXX_Scenario(t *testing.T) { + // Arrange - 准备测试数据 + store := newMockStore() + svc := NewService(store) + + // Act - 执行被测操作 + result, err := svc.DoSomething(ctx, req) + + // Assert - 验证结果 + assert.NoError(t, err) + assert.Equal(t, expected, result) +} +``` + +### 3.2 Mock 接口而非具体实现 + +```go +// ✅ 正确 - Mock 接口 +type mockSettlementStore struct { + settlements map[int64]*Settlement +} + +func (m *mockSettlementStore) GetByID(ctx context.Context, supplierID, id int64) (*Settlement, error) { + if s, ok := m.settlements[id]; ok && s.SupplierID == supplierID { + return s, nil + } + return nil, errors.New("not found") +} + +// ❌ 错误 - Mock 具体类型 +type mockRepo struct { + repo *repository.SettlementRepository +} +``` + +### 3.3 Mock 审计存储正确姿势 + +审计存储使用 `audit.AuditStore` 接口,方法签名为: + +```go +type AuditStore interface { + Emit(ctx context.Context, event audit.Event) error + Query(ctx context.Context, filter audit.EventFilter) ([]audit.Event, error) + QueryWithTotal(ctx context.Context, filter audit.EventFilter) ([]audit.Event, int64, error) + GetByID(ctx context.Context, eventID string) (audit.Event, error) +} +``` + +**错误示例:** +```go +// ❌ 错误 - 使用 interface{} +func (m *mockAuditStore) Emit(ctx context.Context, event interface{}) error { + return nil +} +``` + +**正确示例:** +```go +// ✅ 正确 - 使用具体类型 +func (m *mockAuditStore) Emit(ctx context.Context, event audit.Event) error { + return nil +} +``` + +### 3.4 表驱动测试 + +适用于多场景测试: + +```go +func TestSettlementStatus_Transitions(t *testing.T) { + tests := []struct { + name string + from SettlementStatus + to SettlementStatus + expected bool + }{ + {"pending to processing", SettlementStatusPending, SettlementStatusProcessing, true}, + {"pending to completed", SettlementStatusPending, SettlementStatusCompleted, false}, + // ... + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ValidateStateTransition(tt.from, tt.to) + assert.Equal(t, tt.expected, result) + }) + } +} +``` + +--- + +## 4. 集成测试规范 + +### 4.1 使用 build tag 隔离 + +```go +//go:build integration +// +build integration + +package repository_test + +import ( + "testing" + "github.com/stretchr/testify/assert" + "lijiaoqiao/supply-api/internal/repository" +) + +// IntegrationTestSettlementRepository 需要真实的 PostgreSQL +func TestIntegrationSettlementRepository(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test in short mode") + } + // ... +} +``` + +### 4.2 运行集成测试 + +```bash +# 只运行单元测试(默认) +go test ./... + +# 包含集成测试 +go test -tags=integration ./... + +# 排除集成测试 +go test -short ./... +``` + +--- + +## 5. 覆盖率要求 + +### 5.1 模块覆盖率目标 + +| 模块 | 最低覆盖率 | 当前覆盖率 | 状态 | +|------|-----------|-----------|------| +| domain | 70% | 71.2% | ✅ | +| middleware | 80% | 80.4% | ✅ | +| audit/service | 80% | 83.0% | ✅ | +| audit/handler | 75% | 79.6% | ✅ | +| audit/model | 80% | 93.8% | ✅ | +| audit/sanitizer | 80% | 84.3% | ✅ | +| security | 80% | 88.8% | ✅ | +| iam | 70% | 93.2% | ✅ | + +### 5.2 覆盖率检查命令 + +```bash +# 检查单个模块 +go test -cover ./internal/domain/... + +# 生成覆盖率报告 +go test -coverprofile=coverage.out ./... +go tool cover -html=coverage.out -o coverage.html + +# 检查覆盖率达标情况 +go test -cover ./... 2>&1 | grep -E "(coverage|FAIL)" +``` + +### 5.3 覆盖率未达标处理 + +1. 分析未覆盖代码路径 +2. 添加针对性测试用例 +3. 确认覆盖率达到目标 +4. 禁止强行凑覆盖率而编写无意义测试 + +--- + +## 6. 测试数据管理 + +### 6.1 固定测试数据 + +```go +func TestAccountService_Create(t *testing.T) { + store := newMockAccountStore() + + req := &CreateAccountRequest{ + SupplierID: 1001, // 固定供应商ID + Provider: ProviderOpenAI, // 固定提供商 + AccountType: AccountTypeAPIKey, + Credential: "sk-test-key", // 测试用密钥 + RiskAck: true, + } + + account, err := store.Create(context.Background(), req) + // ... +} +``` + +### 6.2 边界值测试 + +```go +tests := []struct { + name string + input float64 + want bool +}{ + {"zero", 0.0, true}, + {"positive", 100.0, true}, + {"negative", -1.0, false}, + {"very large", 1e10, true}, +} +``` + +--- + +## 7. 测试命名规范 + +### 7.1 函数命名 + +``` +Test{UnitOfWork}_{Scenario}_{ExpectedResult} + +示例: +- TestAccountService_Create_Success +- TestAccountService_Create_InvalidInput +- TestPackageService_Publish_ExpiredPackage +- TestSettlementService_Withdraw_ExceedsBalance +``` + +### 7.2 测试文件内子测试 + +```go +func TestAccountService_Activate(t *testing.T) { + tests := []struct { + name string + setup func() *Account + supplierID int64 + wantErr bool + }{ + { + name: "activate pending account success", + setup: func() *Account { /* ... */ }, + supplierID: 1001, + wantErr: false, + }, + { + name: "activate non-existent fails", + setup: func() *Account { return nil }, + supplierID: 9999, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // ... + }) + } +} +``` + +--- + +## 8. 测试运行策略 + +### 8.1 本地开发 + +```bash +# 快速测试(跳过慢速测试) +go test -short ./... + +# 完整测试(含集成测试) +go test -tags=integration ./... + +# 只测试修改的包 +go test ./internal/domain/... + +# 详细输出 +go test -v ./internal/domain/... +``` + +### 8.2 CI/CD + +```yaml +# .github/workflows/test.yml +name: Test +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.21' + + - name: Run unit tests + run: go test -short -coverprofile=coverage.out ./... + + - name: Run integration tests + run: go test -tags=integration -coverprofile=coverage.out ./... + + - name: Upload coverage + uses: codecov/codecov-action@v3 + with: + files: ./coverage.out +``` + +--- + +## 9. 常见问题处理 + +### 9.1 测试依赖外部服务 + +**问题**: 数据库、Redis、消息队列不可用 + +**解决**: 使用 Mock 替代真实依赖 + +```go +// ❌ 依赖真实存储 +func TestSettlementService(t *testing.T) { + repo, _ := NewPostgresRepository(db) // 需要真实DB +} + +// ✅ 使用 Mock +func TestSettlementService(t *testing.T) { + store := newMockSettlementStore() // 无外部依赖 + svc := NewSettlementService(store, nil, nil) +} +``` + +### 9.2 时间相关测试 + +**问题**: `time.Now()` 导致测试不确定 + +**解决**: 使用依赖注入或时间模拟 + +```go +// 通过参数注入时间或使用 clock 接口 +type SettlementService struct { + store SettlementStore + clock Clock // 注入时间依赖 +} + +func (s *SettlementService) Withdraw(ctx context.Context, supplierID int64, req *WithdrawRequest) (*Settlement, error) { + now := s.clock.Now() + // 使用 now 而非 time.Now() +} +``` + +### 9.3 并发测试 + +**问题**: 竞态条件难以复现 + +**解决**: 使用 `race` 检测器 + +```bash +go test -race ./... +``` + +--- + +## 10. 测试检查清单 + +新代码合并前: + +- [ ] 所有单元测试通过 +- [ ] 覆盖率达标(无下降) +- [ ] 无 `TODO` 或 `FIXME` 遗留测试 +- [ ] Mock 使用正确接口签名 +- [ ] 测试名称符合规范 +- [ ] 表驱动测试覆盖边界情况 +- [ ] 集成测试在 CI 中正常运行 + +--- + +## 11. 参考资料 + +- [Go Testing](https://pkg.go.dev/testing) +- [testify](https://github.com/stretchr/testify) +- [Advanced Testing in Go](https://google.github.io/aip/214) diff --git a/supply-api/reports/test_coverage_report_2026-04-08.md b/supply-api/reports/test_coverage_report_2026-04-08.md new file mode 100644 index 00000000..192e5038 --- /dev/null +++ b/supply-api/reports/test_coverage_report_2026-04-08.md @@ -0,0 +1,189 @@ +# 测试覆盖率报告 + +**生成时间**: 2026-04-08 +**分支**: upload/2026-03-26-sync-clean + +## 摘要 + +| 指标 | 数值 | +|------|------| +| 总测试文件数 | 40+ | +| 单元测试覆盖达标模块 | 7/8 | +| 关键模块平均覆盖率 | 78.4% | + +--- + +## 模块覆盖率详情 + +### ✅ 达标模块 + +| 模块 | 目标 | 实际 | 差距 | +|------|------|------|------| +| domain | 70% | **71.2%** | +1.2% | +| middleware | 80% | **80.4%** | +0.4% | +| audit/handler | 75% | **79.6%** | +4.6% | +| audit/service | 80% | **83.0%** | +3.0% | +| audit/model | 80% | **93.8%** | +13.8% | +| audit/sanitizer | 80% | **84.3%** | +4.3% | +| security | 80% | **88.8%** | +8.8% | +| iam | 70% | **93.2%** | +23.2% | +| pkg/error | 80% | **93.1%** | +13.1% | + +### ⚠️ 需改进模块 + +| 模块 | 目标 | 实际 | 待提升 | +|------|------|------|--------| +| audit/repository | 50% | 0.0% | +50% | +| repository | 50% | 1.3% | +48.7% | +| httpapi | 50% | 6.0% | +44.0% | +| iam/handler | 50% | 23.2% | +26.8% | +| iam/service | 50% | 23.6% | +26.4% | +| iam/middleware | 50% | 24.6% | +25.4% | +| pkg/logging | 50% | 50.0% | 0% | +| middleware | 80% | 52.7% | -27.3% | + +--- + +## Domain 模块详细覆盖 + +### 覆盖率分布 + +| 文件 | 覆盖率 | 状态 | +|------|--------|------| +| account.go | 高 | ✅ | +| package.go | 高 | ✅ | +| settlement.go | 中 | ⚠️ | +| outbox.go | 高 | ✅ | +| compensation.go | 高 | ✅ | +| invariants.go | 高 | ✅ | + +### 未完全覆盖方法 + +``` +settlement.go: + - Withdraw: 0% + - Cancel: 0% + - GetByID: 0% + - List: 0% + - GetBillingSummary: 0% + - generateSettlementNo: 0% + +package.go: + - Clone: 0% (已有测试) + - BatchUpdatePrice: 0% (已有测试) +``` + +--- + +## 测试文件清单 + +### Domain 模块 + +| 文件 | 行数 | 说明 | +|------|------|------| +| account_test.go | ~580 | AccountService 完整测试 | +| package_test.go | ~580 | PackageService 完整测试 | +| settlement_test.go | ~500 | SettlementService 完整测试 | +| invariants_test.go | ~500 | 业务不变量测试 | +| outbox_test.go | ~400 | Outbox 模式测试 | +| compensation_test.go | ~200 | 补偿机制测试 | + +### Audit 模块 + +| 文件 | 行数 | 说明 | +|------|------|------| +| audit_service_test.go | ~300 | 审计服务测试 | +| audit_service_db_test.go | ~200 | 数据库审计测试 | +| alert_service_test.go | ~200 | 告警服务测试 | +| batch_buffer_test.go | ~150 | 批处理测试 | +| audit_handler_test.go | ~400 | 处理器测试 | + +### Middleware 模块 + +| 文件 | 行数 | 说明 | +|------|------|------| +| auth_test.go | ~300 | 认证测试 | +| ratelimit_test.go | ~200 | 限流测试 | +| idempotency_test.go | ~200 | 幂等测试 | +| tracing_test.go | ~150 | 追踪测试 | +| db_token_backend_test.go | ~200 | Token 后端测试 | + +--- + +## Mock 实现清单 + +### Domain Mocks + +```go +// account_test.go +mockAccountStore struct { ... } +mockAuditStore struct { ... } + +// package_test.go +mockPackageStoreForPackageTest struct { ... } +mockAccountStoreForPackageTest struct { ... } +mockAuditStoreForPackageTest struct { ... } + +// invariants_test.go +mockAccountStoreForInvariant struct { ... } +mockPackageStoreForInvariant struct { ... } +mockSettlementStoreForInvariant struct { ... } + +// settlement_test.go +mockSettlementStore struct { ... } +mockEarningStore struct { ... } +mockAuditStoreForSettlement struct { ... } +``` + +--- + +## 测试运行指南 + +### 本地快速验证 + +```bash +# 验证关键模块 +go test -cover ./internal/domain/... \ + ./internal/middleware/... \ + ./internal/audit/handler/... \ + ./internal/audit/service/... +``` + +### 生成覆盖率报告 + +```bash +go test -coverprofile=coverage.out ./... +go tool cover -html=coverage.out -o coverage.html +``` + +### CI 检查 + +```bash +# 检查所有测试通过 +go test ./... + +# 检查覆盖率达标 +go test -cover ./... | grep -v "coverage: 0.0%" +``` + +--- + +## 下一步行动 + +### 短期(1周) + +1. 提升 repository 模块覆盖率(0% → 30%) +2. 提升 httpapi 模块覆盖率(6% → 30%) +3. 补充 middleware 缺失测试 + +### 中期(2周) + +1. 完善 settlement.go 所有方法测试 +2. 补充 IAM 模块 handler/service 测试 +3. 添加集成测试骨架 + +### 长期(1月) + +1. 建立 E2E 测试 +2. 性能测试基线 +3. 混沌测试