Go单元测试中如何Mock NewSchema调用的SubmittingIdentityHasOU函数?
解决Go单元测试中Mock内部函数的问题
针对你遇到的NewSchema调用SubmittingIdentityHasOU时Mock失效的问题,核心原因是Go的静态编译特性——直接调用包内函数会在编译阶段绑定到实际实现,无法直接Mock。以下是两种可行的改造方案:
方案1:将依赖函数改为包级变量
把SubmittingIdentityHasOU定义为包级函数变量,测试时直接替换该变量即可:
改造业务代码
// 定义包级函数变量,默认指向原实现 var SubmittingIdentityHasOU = func(ctx contractapi.TransactionContextInterface, ou string) bool { // 原函数的实际逻辑 } func NewSchema(ctx contractapi.TransactionContextInterface, groupName string, schemaName string, schemaText string) error { // 调用函数变量而非直接调用原函数 if !SubmittingIdentityHasOU(ctx, "random_string") { return errors.New("权限不足") } // 其他业务逻辑 }
编写测试用例
func TestNewSchema_ValidOU(t *testing.T) { // 保存原函数,测试结束后恢复避免影响其他用例 originalFunc := SubmittingIdentityHasOU defer func() { SubmittingIdentityHasOU = originalFunc }() // Mock函数返回true SubmittingIdentityHasOU = func(ctx contractapi.TransactionContextInterface, ou string) bool { return true } // 构造测试用的TransactionContext(需自行Mock接口实现) ctx := mockTransactionContext() err := NewSchema(ctx, "test-group", "test-schema", "{}") if err != nil { t.Fatalf("预期无错误,实际得到:%v", err) } } func TestNewSchema_InvalidOU(t *testing.T) { originalFunc := SubmittingIdentityHasOU defer func() { SubmittingIdentityHasOU = originalFunc }() // Mock函数返回false SubmittingIdentityHasOU = func(ctx contractapi.TransactionContextInterface, ou string) bool { return false } ctx := mockTransactionContext() err := NewSchema(ctx, "test-group", "test-schema", "{}") if err == nil { t.Fatal("预期返回权限不足错误,实际无错误") } if err.Error() != "权限不足" { t.Fatalf("错误信息不符,预期:权限不足,实际:%v", err.Error()) } }
方案2:通过接口依赖注入封装
如果业务逻辑复杂,推荐用接口封装依赖,实现更清晰的解耦:
改造业务代码
// 定义权限检查接口 type IdentityChecker interface { HasOU(ctx contractapi.TransactionContextInterface, ou string) bool } // 默认实现原函数逻辑 type DefaultIdentityChecker struct{} func (d *DefaultIdentityChecker) HasOU(ctx contractapi.TransactionContextInterface, ou string) bool { // 原函数的实际逻辑 } // 将检查器作为结构体字段,实现依赖注入 type SchemaService struct { checker IdentityChecker } // 构造函数,默认使用默认检查器 func NewSchemaService() *SchemaService { return &SchemaService{ checker: &DefaultIdentityChecker{}, } } // 把NewSchema改为结构体方法,依赖接口而非直接调用函数 func (s *SchemaService) NewSchema(ctx contractapi.TransactionContextInterface, groupName string, schemaName string, schemaText string) error { if !s.checker.HasOU(ctx, "random_string") { return errors.New("权限不足") } // 其他业务逻辑 }
编写测试用例
// 定义Mock检查器 type MockIdentityChecker struct { hasOUResult bool } func (m *MockIdentityChecker) HasOU(ctx contractapi.TransactionContextInterface, ou string) bool { return m.hasOUResult } func TestNewSchema_ValidOU(t *testing.T) { // 创建Mock检查器,指定返回true mockChecker := &MockIdentityChecker{hasOUResult: true} service := &SchemaService{checker: mockChecker} ctx := mockTransactionContext() err := service.NewSchema(ctx, "test-group", "test-schema", "{}") if err != nil { t.Fatalf("预期无错误,实际得到:%v", err) } } func TestNewSchema_InvalidOU(t *testing.T) { mockChecker := &MockIdentityChecker{hasOUResult: false} service := &SchemaService{checker: mockChecker} ctx := mockTransactionContext() err := service.NewSchema(ctx, "test-group", "test-schema", "{}") if err == nil { t.Fatal("预期返回权限不足错误,实际无错误") } if err.Error() != "权限不足" { t.Fatalf("错误信息不符,预期:权限不足,实际:%v", err.Error()) } }
内容的提问来源于stack exchange,提问作者Fernando Garzón
相关产品推荐
相关产品推荐

