测试和模拟不返回任何值的函数

时间:2018-01-03 18:08:31

标签: unit-testing go mocking gomock

我想测试一个函数,它不返回任何值,而是触发其他函数。在阅读测试时,我发现这被称为行为验证的信息,通过模拟,我可以检查触发的功能和顺序。但是,我有一个问题是为我的代码实现正确的模拟技术。

让我们考虑以下接口和结构的一个简单示例(该示例非常基本,只是为了更容易解释):

type ExampleInterface interface {
    DoSomething(arg int)
    DoEvenMore(arg int)
    AndEvenMore(arg int)
} 

type ExampleStruct struct {
     Id string 
     // Other fields
}

func (e *ExampleStruct) DoSomething(arg int) {
     arg2 := arg * 2
     e.DoEvenMore(arg2)
     arg3 := arg * 3
     e.AndEvenMore(arg3)  
}

func (e *ExampleStruct) DoEvenMore(arg int){
     fmt.Println("I did so many operations here using ", arg)
}

func (e *ExampleStruct) AndEvenMore(arg int) {
     // Performing other operations on arg
}

现在,我想测试函数DoSomething。因为它没有返回任何值,我想要做的是测试在使用参数3调用此函数之后是否发生以下事件链:函数DoEvenMore使用参数6调用一次,并且下一个函数使用参数AndEvenMore

调用9一次

我写了以下模拟测试:

func TestDoSomething(t *testing.T) {

    mockCtrl := gomock.NewController(t)
    defer mockCtrl.Finish()

    mockClient := mocks.NewMockExampleInterface(mockCtrl)

    example := ExampleStruct("ExampleId")

    gomock.InOrder(
        mockClient.EXPECT().DoSomething(3).Return().Times(1)
        mockClient.EXPECT().DoEvenMore(6).Return().Times(1)
        mockClient.EXPECT().AndEvenMore(9).Return().Times(1) 
    )

    example.DoSomething(3)
}

但是,当我运行此测试时,我收到错误:Unexpected call to *mocks.MockExampleInterface.DoSomething(..)

如何在这样的例子中正确执行模拟?

1 个答案:

答案 0 :(得分:3)

DoSomething调用的两个方法是具体的实现,你不能在Go中模仿这样的东西。

要在定义这两种方法的接口上实现您想要的DoSomething 依赖,并调用它们而不是具体的方法。

type DoMorer interface {
    DoEvenMore(arg int)
    AndEvenMore(arg int)
} 

type ExampleStruct struct {
     Id string 
     // Other fields
}

func (e *ExampleStruct) DoSomething(arg int, dm DoMorer) {
     arg2 := arg * 2
     dm.DoEvenMore(arg2)
     arg3 := arg * 3
     dm.AndEvenMore(arg3)  
}

使用这样的设置,在测试期间,您可以为DoMorer界面创建模拟并将其传递给DoSomething

DoMorer不必作为参数传递,它可以是ExampleStruct或全局的字段,无论您的需求是什么。