You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang表格驱动测试中如何为不同子测试设置不同Mock?

解决Go表格驱动测试中Mock变量的隔离问题

你当前的测试代码里,mockStr定义在Test_funcTest的函数作用域内,属于所有子测试共享的变量,test1修改它后会影响test2的执行,导致测试相互污染。以下是几种可行的解决方法:

方法1:给测试用例结构体添加专属Mock字段

把每个测试用例需要的mockStr值加到测试结构体中,在子测试执行前单独设置这个变量,确保每个子测试使用自己的Mock值。

func Test_funcTest(t *testing.T) {
    type args struct {
        arg1 string
        arg2 string
    }
    // 测试结构体新增mockStr字段,存储当前用例的专属Mock值
    tests := []struct {
        name    string
        args    args
        want    string
        wantErr bool
        mockStr string
    }{
        {
            name:    "test1",
            args:    args{arg1: "arg1", arg2: "arg2"},
            want:    "res1",
            wantErr: false,
            mockStr: "mock1", // test1的专属Mock值
        },
        {
            name:    "test2",
            args:    args{arg1: "arg1", arg2: "arg2"},
            want:    "res2",
            wantErr: false,
            mockStr: "mock2", // test2的专属Mock值
        },
    }
    for _, tt := range tests {
        tt := tt // 捕获循环变量,避免闭包引用问题
        t.Run(tt.name, func(t *testing.T) {
            // 子测试中设置当前用例的Mock值
            mockStr = tt.mockStr
            got, err := funcTest(tt.args.arg1, tt.args.arg2)
            if (err != nil) != tt.wantErr {
                t.Errorf("funcTest() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if got != tt.want {
                t.Errorf("funcTest() = %v, want %v", got, tt.want)
            }
        })
    }
}

方法2:使用t.Cleanup()恢复原始值

如果mockStr是全局变量或无法直接嵌入测试结构体,可以在子测试修改前保存原始值,通过t.Cleanup()在测试结束后恢复,确保每个子测试的修改不会污染其他测试。

func Test_funcTest(t *testing.T) {
    type args struct {
        arg1 string
        arg2 string
    }
    tests := []struct {
        name    string
        args    args
        want    string
        wantErr bool
        mockStr string
    }{
        {
            name:    "test1",
            args:    args{arg1: "arg1", arg2: "arg2"},
            want:    "res1",
            wantErr: false,
            mockStr: "mock1",
        },
        {
            name:    "test2",
            args:    args{arg1: "arg1", arg2: "arg2"},
            want:    "res2",
            wantErr: false,
            mockStr: "mock2",
        },
    }
    for _, tt := range tests {
        tt := tt
        t.Run(tt.name, func(t *testing.T) {
            // 保存当前mockStr的原始值
            prevMock := mockStr
            // 测试结束后自动恢复原始值
            t.Cleanup(func() {
                mockStr = prevMock
            })
            // 设置当前测试的Mock值
            mockStr = tt.mockStr
            got, err := funcTest(tt.args.arg1, tt.args.arg2)
            if (err != nil) != tt.wantErr {
                t.Errorf("funcTest() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if got != tt.want {
                t.Errorf("funcTest() = %v, want %v", got, tt.want)
            }
        })
    }
}

方法3:重构代码使用依赖注入(推荐)

这是最彻底的解决方案,让funcTest不依赖外部的mockStr变量,而是通过参数传入需要的字符串,从根源上避免测试污染问题。

重构后的funcTest:

func funcTest(arg1, arg2, mockStr string) (string, error) {
    // 原逻辑改为使用传入的mockStr参数
    // ...
}

对应的测试代码:

func Test_funcTest(t *testing.T) {
    type args struct {
        arg1    string
        arg2    string
        mockStr string // 将mockStr作为测试参数传入
    }
    tests := []struct {
        name    string
        args    args
        want    string
        wantErr bool
    }{
        {
            name: "test1",
            args: args{
                arg1:    "arg1",
                arg2:    "arg2",
                mockStr: "mock1",
            },
            want:    "res1",
            wantErr: false,
        },
        {
            name: "test2",
            args: args{
                arg1:    "arg1",
                arg2:    "arg2",
                mockStr: "mock2",
            },
            want:    "res2",
            wantErr: false,
        },
    }
    for _, tt := range tests {
        tt := tt
        t.Run(tt.name, func(t *testing.T) {
            got, err := funcTest(tt.args.arg1, tt.args.arg2, tt.args.mockStr)
            if (err != nil) != tt.wantErr {
                t.Errorf("funcTest() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if got != tt.want {
                t.Errorf("funcTest() = %v, want %v", got, tt.want)
            }
        })
    }
}

内容的提问来源于stack exchange,提问作者Mihika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:44:52