【问题标题】:How to create a mock inside the function under test如何在被测函数内创建模拟
【发布时间】:2020-06-14 20:04:51
【问题描述】:

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

让我们说:

// 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
}

有没有办法测试整个这个功能?我可以创建包装 SomeMethod() 的接口 SomeMethoder,但我找不到如何将其分配给 obj >SomeFunc 不将 GetObject 的签名更改为 GetObject(id int) SomeMethoder,error

目前我看到了一种方法——按零件进行测试。

【问题讨论】:

  • 如果你想让GetObject返回一个mockable实例,你必须改变签名。但是,您应该重新考虑是否真的需要一个模拟来测试该功能,也许 ObjectGetter 模拟可以返回一个 ObjectType 的实例,该实例无需引入另一个模拟即可轻松测试。
  • 主要问题完全源于嘲笑。停止嘲笑其他语言推广它的方式。你有一个 ObjectGeter 接口,并且要测试 SomeFun 你必须提供和正常工作的 ObjectGeter:它必须提供 Objects 并且这些必须有 SomeMethod。无需尝试注入模拟僵尸,而是提供具有正确、已知、一致且因此可测试状态的正确对象。不要嘲笑。写假货或存根。

标签: go testing mocking


【解决方案1】:

我发现的唯一不改变范式的解决方案是包装器。这很简单,但可能有人需要它一次。

原来我有一些类型:

type PoolType struct {...}

func (p *PoolType)GetObject(id int) (ObjectType, error) {...}

和接口,它包装了 PoolType.GetObject 并且我已经嘲笑过了。

现在我有了界面:

type SomeMethoder interface {
    SomeMethod() (ResultType, error)
}

包装由PoolType.GetObject()返回的对象。

要生产它,我有接口:

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)
}

实现它。

所以:

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

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

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

    return rezult, nil
}

被调用

og := New(pool)
SomeFunc(og,id,otherArgument)

在实际工作中。

毕竟要测试整个 SomeFunc 我必须:

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,这对我来说已经足够了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 2020-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多