本文档规范项目的代码质量要求,包括单元测试、Lint 检查和 Code Review。 编写代码必须符合 项目根目录下的.golangci.yml中的规范
| 目录 | 覆盖率要求 | 说明 |
|---|---|---|
| pkg/ | ≥ 90% | 公共库需要高覆盖率 |
| app/logic/ | ≥ 80% | Logic 业务逻辑层 |
| app/manager/ | ≥ 80% | Manager 复用层 |
以下文件不计入覆盖率统计:
*.pb.go- Protobuf 生成的代码mock_*.go- Mock 生成的代码
# 运行所有测试
make test
# 或直接运行测试脚本
bash script/test/unit_test/unit_test.sh
# 运行特定目录的测试
go test ./pkg/... -cover
go test ./app/apis/stayy/api/internal/logic/... -cover测试文件与源文件放在同一目录,命名为 {源文件名}_test.go:
internal/logic/user_logic.go
internal/logic/user_logic_test.go
package apiv1
import (
"context"
"testing"
"apps/app/apis/stayy/api/internal/svc"
"apps/app/apis/stayy/api/internal/repository/mocks"
"github.com/golang/mock/gomock"
)
func TestUserLogic_WXMiniAuth(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
// 创建 Mock 依赖
mockUserSrv := mocks.NewMockUserSrvType(ctrl)
mockThirdAuthManager := mocks.NewMockThirdAuthManager(ctrl)
svcCtx := &svc.ServiceContext{
Repo: &repository.Repository{
UserSrv: mockUserSrv,
WXMiniAuthClient: mockThirdAuthManager,
},
}
logic := NewUserLogic(svcCtx)
// 设置 Mock 期望
mockThirdAuthManager.EXPECT().GetClient("wxMini").Return(nil, nil)
// 执行测试
resp, err := logic.WXMiniAuth(context.Background(), &pb.WXMiniAuthReq{
Code: "test_code",
})
// 断言
assert.NoError(t, err)
assert.NotNil(t, resp)
}使用描述性的测试函数名:
// ✅ 正确
func TestUserLogic_CreateUser_Success(t *testing.T) {}
func TestUserLogic_CreateUser_InvalidParam(t *testing.T) {}
func TestUserLogic_CreateUser_DuplicateUser(t *testing.T) {}
// ❌ 错误
func TestUserLogic1(t *testing.T) {}
func TestUserLogicCreateUserCase1(t *testing.T) {}func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{
name: "valid email",
email: "[email protected]",
wantErr: false,
},
{
name: "empty email",
email: "",
wantErr: true,
},
{
name: "invalid format",
email: "invalid-email",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateEmail(tt.email)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}确保接口文件包含 //go:generate 指令:
//go:generate mockgen -package rpc -destination mock_user_service.go apps/pb/services/core/user/v1 UserServiceClient执行 make mock 生成 Mock 文件。
# 运行 golangci-lint
make lint
# 或直接运行
golangci-lint run --timeout=5m| 规则 | 说明 | 违规示例 |
|---|---|---|
| 禁止导入 | 禁止使用 go-zero/core/logx |
import "github.com/zeromicro/go-zero/core/logx" |
| 函数长度 | 函数不超过 80 行(handler 除外) | 长函数应拆分 |
| 自动格式化 | 使用 goimports, gofumpt |
代码格式统一 |
禁止使用 github.com/zeromicro/go-zero/core/logx
必须使用 apps/pkg/xlog
// ❌ 错误
import "github.com/zeromicro/go-zero/core/logx"
logx.Error("error message")
// ✅ 正确
import "apps/pkg/xlog"
xlog.Errorf(ctx, "error message")make format这会运行:
goimports- 整理 importgofumpt- 代码格式化
- 服务类型划分正确(core/shared/support)
- 职责清晰,无循环依赖
- 接口设计符合原子服务原则(方案二)或领域服务原则(方案三)
- Proto 文件定义规范
- Service 和 RPC 方法有
@Desc注解 - 命名符合约定(PascalCase for Service/Message, snake_case for fields)
- 错误码已在
error_prefix.proto中定义前缀
- 目录结构符合规范
- Repository 包含
repository.go和repository_type.go - Model 包含
//go:generate mockgen指令 - Logic/Service 结构清晰
- 使用
apps/pkg/xerr定义错误 - 错误返回带日志记录
- 区分业务错误和系统错误
- 不使用
github.com/zeromicro/go-zero/core/logx
- 使用
apps/pkg/xlog记录日志 - 日志包含上下文信息(如 user_id, order_id)
- 日志级别正确(Info/Error/Debug)
- 第一个参数传递
context.Context
- 使用生成的 Model 方法
- 自定义方法写在
*_model.go中 - 局部更新调用
updatePartial - 事务使用
model.Transaction()
- Logic/Manager 层有单元测试
- 使用 Mock 隔离依赖
- 覆盖率符合要求(pkg ≥ 90%, app/logic+biz ≥ 80%)
- 测试用例命名清晰
- 通过
golangci-lint检查 - 代码格式符合
gofumpt规范 - Import 已整理(
goimports) - 无未使用的代码
- 自检:提交 PR 前执行
make lint和make test - 提交 PR:确保 PR 描述清晰,包含改动说明
- 通过 Review:至少一人 Review 通过后合并
| 问题 | 解决方案 |
|---|---|
| 覆盖率不足 | 补充单元测试用例 |
| Lint 失败 | 运行 make format 自动修复 |
| 导入禁用包 | 替换为 apps/pkg/xlog |
| Mock 生成失败 | 检查 //go:generate 指令是否存在 |