测试和模拟一个没有 return 任何值的函数
Testing and mocking a function which does not return any value
我想测试一个函数,它没有 return 任何值,而是触发其他函数。在阅读有关测试的信息时,我发现这称为行为验证的信息,并且通过模拟我可以检查触发了哪些功能以及触发顺序。但是,我在为我的代码实施正确的模拟技术时遇到了问题。
让我们考虑以下接口和结构的一个简单示例(示例非常基础只是为了更容易解释):
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
。由于它没有 return 任何值,我想做的是测试在使用参数 3 调用此函数后是否会发生以下事件链:使用参数 6
调用函数 DoEvenMore
一次,下一个函数 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(..)
。
在这样的例子中我应该如何正确地执行模拟?
DoSomething
调用的两个方法是具体的实现,在Go中是不能mock的。
要实现您想要的 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
的字段或全局字段,只要满足您的需要即可。
我想测试一个函数,它没有 return 任何值,而是触发其他函数。在阅读有关测试的信息时,我发现这称为行为验证的信息,并且通过模拟我可以检查触发了哪些功能以及触发顺序。但是,我在为我的代码实施正确的模拟技术时遇到了问题。
让我们考虑以下接口和结构的一个简单示例(示例非常基础只是为了更容易解释):
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
。由于它没有 return 任何值,我想做的是测试在使用参数 3 调用此函数后是否会发生以下事件链:使用参数 6
调用函数 DoEvenMore
一次,下一个函数 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(..)
。
在这样的例子中我应该如何正确地执行模拟?
DoSomething
调用的两个方法是具体的实现,在Go中是不能mock的。
要实现您想要的 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
的字段或全局字段,只要满足您的需要即可。