模拟结构';go测试中的s方法调用

模拟结构';go测试中的s方法调用,go,testing,methods,struct,mocking,Go,Testing,Methods,Struct,Mocking,我希望在测试中模拟结构的方法,以提高代码覆盖率。 有一些关于这个的帖子,没有一个是为我工作的。我可能完全弄错了 main/file1.go type application struct { Name string } func (app *application) find() error { // perform function logic return nil } func main() { app := &application{

我希望在测试中模拟结构的方法,以提高代码覆盖率。 有一些关于这个的帖子,没有一个是为我工作的。我可能完全弄错了

main/file1.go

type application struct {
    Name string
 }

func (app *application) find() error {
    // perform function logic
    return nil
}

func main() {
    app := &application{
        Name:   "Main Application",
    }

    err := app.find()
    if err != nil {
        fmt.Printf("Error in find call: %s\n", err)
    }
}
func Test_application_find(t *testing.T) {
    tests := []struct {
        name           string
        app            *application
        wantErr        string
    }{
        {
            name: "generate error",
            app: &application{
                Name: "Mock Application",
            },
            wantErr: true,
        },
    }
    for _, tt := range tests {
        mockCaller := tt.app.find // this works fine
        tt.app.find = func() error { // this assignment errors out
            return fmt.Errorf("Mock Error Message")
        }
        defer func() {
            tt.app.find = mockCaller // this assignment errors out
        }()

        t.Run(tt.name, func(t *testing.T) {
            if err := tt.app.find(); (err != nil) && (err.Error() != "Mock Error Message") {
                    t.Errorf("error = %s, wantErr %s", err.Error(), tt.wantErr)
            }
        } 
    }
}
我需要能够模拟测试
find()
并返回
错误
(我不希望生成可能导致错误的测试用例,因为这不在我的控制之下,我不确定如何通过传递可接受的参数来生成一个测试用例)。 我试着按照帖子的第二个答案去做,但编译器不喜欢

main/file1\u test.go

type application struct {
    Name string
 }

func (app *application) find() error {
    // perform function logic
    return nil
}

func main() {
    app := &application{
        Name:   "Main Application",
    }

    err := app.find()
    if err != nil {
        fmt.Printf("Error in find call: %s\n", err)
    }
}
func Test_application_find(t *testing.T) {
    tests := []struct {
        name           string
        app            *application
        wantErr        string
    }{
        {
            name: "generate error",
            app: &application{
                Name: "Mock Application",
            },
            wantErr: true,
        },
    }
    for _, tt := range tests {
        mockCaller := tt.app.find // this works fine
        tt.app.find = func() error { // this assignment errors out
            return fmt.Errorf("Mock Error Message")
        }
        defer func() {
            tt.app.find = mockCaller // this assignment errors out
        }()

        t.Run(tt.name, func(t *testing.T) {
            if err := tt.app.find(); (err != nil) && (err.Error() != "Mock Error Message") {
                    t.Errorf("error = %s, wantErr %s", err.Error(), tt.wantErr)
            }
        } 
    }
}

我做错了什么?请提出建议。

模拟方法有几种方法。他们都有自己擅长的情况

作文 对于测试,在原始结构的基础上创建一个新结构

struct testApp struct{
应用
}
现在,
teststruct
的行为方式与
app
几乎相同,但您可以覆盖find函数:

func(app*testApp)find()错误{
返回错误。新建(“某些错误”)
}
在测试中,您使用适当的
app
初始化
testApp

app:=testApp{
应用程序:&应用程序{
名称:“模拟应用程序”,
}
}
现在,您可以在
app
变量上编写测试

注意,这并不适用于所有用例,因为组合不是继承。在原始
应用程序上调用函数
不会调用
testApp
中的新
find
函数

接口 您还可以模拟测试所需的整个应用程序结构/部分。如果您想测试另一个依赖于
应用程序的结构,这通常是有意义的

要测试的结构不应直接使用
应用程序
,而应使用其所需功能的接口。(这可能意味着重构代码以实现此目的。)

然后使用mock
find
函数创建一个mock,并将该mock传递给要测试的结构:

类型应用程序界面{
find()错误
}
类型mockApp struct{
名称字符串
}
(s*mockApp)查找()错误{
返回错误。新建(“某些错误”)
}
结构域 您还可以将
find
函数设置为结构字段。然后您可以出于测试目的覆盖它。然而,这样做的缺点是必须更改代码

类型应用程序结构{
名称字符串
find func()错误
}
编写创建者,使其能够以合理的方式初始化结构:

func newApplication()*应用程序{
退货与申请{
名称:“主应用程序”,
查找:func()错误{
//执行功能逻辑
归零
}
}
}
现在,您可以在测试中覆盖
find
方法(实际上它现在是一个字段):

app:=newApplication()
app.find=func()错误{
返回错误。新建(“某些错误”)
}

在我看来,
接口
是最接近的方法。如果这意味着您要模拟要测试的代码,那么请考虑将代码拆分为多个结构:要测试的代码(
应用程序
)和要模拟的
查找程序
结构/接口。在我看来,
find
更像是一种依赖。你还说,你不能轻易影响它的结果。谢谢你的回答!如果它对你有帮助的话,请随意将其标记为正确答案。