Go 如何在被测函数内部创建模拟

Go 如何在被测函数内部创建模拟,go,testing,mocking,Go,Testing,Mocking,我有一组函数,它们使用对象池。这个游泳池已经被嘲笑了。它在大多数情况下都能正常工作。但在某些函数中,我从池中调用对象的方法。所以我也需要模拟这些对象 让我们说: // ObjectGeter is a interface that is mocked type ObjectGeter interface { GetObject(id int) ObjectType, error } // this function is under test func SomeFunc(og Obj

我有一组函数,它们使用对象池。这个游泳池已经被嘲笑了。它在大多数情况下都能正常工作。但在某些函数中,我从池中调用对象的方法。所以我也需要模拟这些对象

让我们说:

// ObjectGeter is a interface that is mocked
type ObjectGeter interface {
    GetObject(id int) ObjectType, error
}

// this function is under test 
func SomeFunc(og ObjectGeter,id int, otherArgument SomeType) error {
    // some actions with otherArgument  
    // and may be return an error

    obj, err := og.GetObject(id)
    if err !=nil {
        return errors.New("GetObject error")
    }

    rezult, err := obj.SomeMethod()
    if err !=nil {
        return errors.New("One of internal errors")
    }

    return rezult, nil
}
有没有办法测试整个功能?我可以创建接口SomeMethoder,该接口封装了SomeMethod(),但是我找不到如何在SomeFunc内部将其分配给obj,而不将GetObject的签名更改为GetObject(id int)SomeMethoder,错误


目前,我看到了一种方法——通过部件进行测试。

我发现的唯一不改变范例的解决方案是包装器。这是相当琐碎,但可能有人会需要它一次

最初我有一些类型:

type PoolType struct {...}

func (p *PoolType)GetObject(id int) (ObjectType, error) {...}
还有一个接口,它包装了PoolType.GetObject,我对它进行了模拟

现在我有了界面:

type SomeMethoder interface {
    SomeMethod() (ResultType, error)
}
type ObjectGeter interface {
    GetObject(id int) (SomeMethoder, error)
}
包装由PoolType.GetObject()返回的对象

要生成它,我有接口:

type SomeMethoder interface {
    SomeMethod() (ResultType, error)
}
type ObjectGeter interface {
    GetObject(id int) (SomeMethoder, error)
}
和类型

type MyObjectGeter struct {
    pool *PoolType
}

func New(pool *PoolType) *MyObjectGeter {
    return &MyObjectGeter{pool: pool}
}

func (p *MyObjectGeter)GetObject(id int) (SomeMethoder, error) {
    return p.pool.GetObject(id)
}
这就实现了它

因此:

被称为

og := New(pool)
SomeFunc(og,id,otherArgument)
在实际工作中

毕竟,要测试整个函数,我必须:

func TestSomeFuncSuccess (t *testing.T) {
    controller := gomock.NewController(t)
    defer controller.Finish()

    objectGeter := mocks.NewMockObjectGeter(controller)
    someMethoder := mocks.NewMockSomeMethoder(controller)

    gomock.InOrder(
        args.objectGeter.EXPECT().
            GetObject(correctIdCOnst).
            Return(someMethoder, nil),
        args.someMethoder.EXPECT().
            SomeMethod().
            Return(NewResultType(...),nil).
            Times(args.test.times[1]),
    )

    result, err := SomeFunc(objectGeter,correctIdCOnst,otherArgumentConst)
    // some checks
}

因此,唯一未测试的部分是MyObjectGeter.GetObject,这对我来说已经足够了。

如果希望
GetObject
返回可模拟的实例,则必须更改签名。然而,您应该重新考虑是否真的需要一个mock来测试该功能,也许ObjectGetter mock可以返回一个ObjectType的实例,该实例在不引入另一个mock的情况下很容易测试。主要的问题完全源于mock。停止嘲笑其他语言推广它的方式。您已经有了一个ObjectGeter接口,为了测试您必须提供的一些乐趣和ObjectGeter是否正常工作:它必须提供对象,而这些对象必须有一些方法。与其尝试注入模拟僵尸,不如提供具有适当、已知、一致和可测试状态的适当对象。不要嘲笑。写赝品或存根。