使用GoMock包进行单元测试的最佳实践

使用GoMock包进行单元测试的最佳实践 需求: 在模拟一个函数时,传入了一个空参数,该参数应在函数内部被填充。 使用 gomock.Matcher 可以通过强制赋值实现,但使用 gomock.AssignableToTypeOf 会失败。 需要在不使用匹配器的情况下实现此功能。

示例:

func main() {
    fmt.Println("hello world")
}
1 回复

在GoMock中处理函数内部填充参数的情况,可以通过DoSetArg方法实现。以下是具体实现方案:

package main

import (
    "testing"
    "github.com/golang/mock/gomock"
)

// 定义接口
type DataProcessor interface {
    Process(data *InputData) error
}

type InputData struct {
    ID   string
    Name string
}

// 测试示例
func TestProcessData(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    mockProcessor := NewMockDataProcessor(ctrl)
    
    // 创建空参数
    input := &InputData{}
    
    // 使用Do函数在调用时填充参数
    mockProcessor.EXPECT().
        Process(gomock.Any()).
        Do(func(arg *InputData) {
            // 在调用时填充参数
            arg.ID = "123"
            arg.Name = "test"
        }).
        Return(nil)
    
    // 执行测试
    err := mockProcessor.Process(input)
    if err != nil {
        t.Fatalf("Process failed: %v", err)
    }
    
    // 验证参数已被填充
    if input.ID != "123" || input.Name != "test" {
        t.Errorf("Expected ID=123, Name=test, got ID=%s, Name=%s", input.ID, input.Name)
    }
}

对于需要修改特定位置参数的情况,可以使用SetArg

func TestProcessWithSetArg(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    mockProcessor := NewMockDataProcessor(ctrl)
    
    input := &InputData{}
    
    mockProcessor.EXPECT().
        Process(gomock.Any()).
        SetArg(0, InputData{ID: "456", Name: "example"}).
        Return(nil)
    
    err := mockProcessor.Process(input)
    if err != nil {
        t.Fatalf("Process failed: %v", err)
    }
    
    if input.ID != "456" || input.Name != "example" {
        t.Errorf("Expected ID=456, Name=example, got ID=%s, Name=%s", input.ID, input.Name)
    }
}

对于需要更复杂逻辑的情况,可以结合使用Do和类型断言:

func TestProcessWithComplexLogic(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    mockProcessor := NewMockDataProcessor(ctrl)
    
    input := &InputData{}
    
    mockProcessor.EXPECT().
        Process(gomock.Any()).
        Do(func(arg interface{}) {
            if data, ok := arg.(*InputData); ok {
                data.ID = "789"
                data.Name = "complex"
                // 可以添加更多业务逻辑
            }
        }).
        Return(nil)
    
    err := mockProcessor.Process(input)
    if err != nil {
        t.Fatalf("Process failed: %v", err)
    }
    
    if input.ID != "789" || input.Name != "complex" {
        t.Errorf("Expected ID=789, Name=complex, got ID=%s, Name=%s", input.ID, input.Name)
    }
}

这些方法避免了使用gomock.Matchergomock.AssignableToTypeOf,直接在模拟调用时修改传入的参数值。Do方法适用于需要执行自定义逻辑的情况,而SetArg方法适用于直接替换参数值的简单场景。

回到顶部