跳到主要内容

测试体系概述

井云服务中心采用分层测试策略,确保代码质量和系统稳定性。本文档介绍项目的测试体系架构和核心概念。

测试架构

测试分层

项目采用以下测试分层策略:

┌─────────────────────────────────────┐
│ 端到端测试 (E2E Tests) │
│ (Playwright - 前端) │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ 集成测试 (Integration Tests) │
│ (服务间通信 + 数据库) │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ 单元测试 (Unit Tests) │
│ (业务逻辑 + Mock 依赖) │
└─────────────────────────────────────┘

测试工具

  • 单元测试: testify + go-sqlmock
  • 前端测试: Playwright
  • 代码覆盖率: go test -cover
  • Mock 框架:
    • Gateway 服务: 手动函数字段 mock
    • 数据库服务: sqlmock + Ent ORM

测试覆盖率要求

类型最低要求理想目标说明
单元测试90%95%+核心业务逻辑必须达到 95%+
集成测试70%85%+服务间通信和数据库操作
端到端测试50%70%+关键用户流程

服务测试状态

服务测试文件数覆盖率规范符合性风险等级
agent16个93.5%✅ 完全符合🟢 低
user8个良好✅ 完全符合🟡 中
tenant7个一般⚠️ 部分符合🟡 中
payment5个良好✅ 完全符合🟡 中
auth4个良好✅ 完全符合🟡 中
cron3个一般⚠️ 部分符合🟡 中
integration1个极差❌ 不符合🔴 高
gateway5个0.0%❌ 不符合🔴 极高

测试策略

1. 单元测试策略

目标: 验证单个函数或方法的正确性

原则:

  • 快速执行 (毫秒级)
  • 无外部依赖
  • 100% 隔离
  • 覆盖所有分支

示例:

func TestCreateAgentCategory(t *testing.T) {
tests := []struct {
name string
req *agentv1.CreateAgentCategoryRequest
want *agentv1.CreateAgentCategoryReply
wantErr error
}{
{
name: "成功创建分类",
req: &agentv1.CreateAgentCategoryRequest{Name: "测试分类"},
want: &agentv1.CreateAgentCategoryReply{Id: 1},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 测试逻辑
})
}
}

2. 集成测试策略

目标: 验证服务间协作和数据库操作

原则:

  • 使用真实的数据库连接 (或 sqlmock)
  • 测试完整的事务流程
  • 验证数据一致性

示例:

func TestCreateAgentWithDatabase(t *testing.T) {
mockDB, mock, svc := setupServiceTest(t)
defer mockDB.Close()

// Mock SQL 查询
rows := sqlmock.NewRows([]string{"id"}).AddRow(int64(101))
mock.ExpectQuery(`INSERT INTO "agent_categories"`).
WillReturnRows(rows)

resp, err := svc.CreateAgentCategory(context.Background(), req)
require.NoError(t, err)
require.Equal(t, int64(101), resp.Id)

require.NoError(t, mock.ExpectationsWereMet())
}

3. Mock 策略

Gateway 服务 - 函数字段 Mock

type MockAgentCategoryClient struct {
CreateAgentCategoryFunc func(ctx context.Context, in *agentv1.CreateAgentCategoryRequest, opts ...grpc.CallOption) (*agentv1.CreateAgentCategoryReply, error)
}

func (m *MockAgentCategoryClient) CreateAgentCategory(ctx context.Context, in *agentv1.CreateAgentCategoryRequest, opts ...grpc.CallOption) (*agentv1.CreateAgentCategoryReply, error) {
return m.CreateAgentCategoryFunc(ctx, in, opts...)
}

数据库服务 - sqlmock + Ent

func setupServiceTest(t *testing.T) (*sql.DB, sqlmock.Sqlmock, *YourService) {
mockDB, mock, err := sqlmock.New()
require.NoError(t, err)

drv := entsql.OpenDB("postgres", mockDB)
entClient := entclient.NewClient(entclient.Driver(drv))

// 初始化服务
svc := NewYourService(entClient, logger)

return mockDB, mock, svc
}

测试规范

核心原则

  1. 字段验证完整性: 返回的结构体所有字段都必须验证
  2. 错误场景覆盖: 必须测试所有可能的错误情况
  3. 边界条件测试: 测试空值、零值、最大值等边界条件
  4. 并发安全测试: 对于并发操作,必须测试并发安全性

完整字段验证示例

// ❌ 错误 - 字段验证不完整
assert.Equal(t, int64(1), resp.Category.Id)
assert.Equal(t, "测试分类", resp.Category.Name)

// ✅ 正确 - 验证所有字段
assert.Equal(t, int64(1), resp.Category.Id)
assert.Equal(t, int64(1), resp.Category.TenantId)
assert.Equal(t, "测试分类", resp.Category.Name)
assert.Equal(t, "测试描述", resp.Category.Description)
assert.Equal(t, int32(1), resp.Category.SortOrder)
assert.False(t, resp.Category.IsFeatured)
assert.True(t, resp.Category.IsActive)
assert.Equal(t, int64(1672531200), resp.Category.CreatedAt)
assert.Equal(t, int64(1672531200), resp.Category.UpdatedAt)

测试执行

运行单个服务测试

cd services/agent
go test ./internal/service/... -v

生成覆盖率报告

go test ./internal/service/... -coverprofile=coverage.out
go tool cover -html=coverage.out -o coverage.html

批量运行所有测试

cd backend
make test-coverage-summary # 生成测试覆盖率汇总
make test-coverage-html # 生成 HTML 覆盖率报告
make test-coverage-report # 生成综合覆盖率报告

下一步