Golang常见mock库小结
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
1. 引言
本文是一篇对mock库的小结。
2. 怎么理解mock这件事
2.1 为什么需要mock
最常见的场景是,一个服务B和它依赖的上游微服务A同时启动开发。为了加快开发速度,服务B不可能等到服务A开发完,在启动开发。因此服务A和服务B约定它们之间交互的接口,然后就可以启动开发了。
服务B为了验证自身的业务逻辑,它需要mock一个A服务(只需要mock相关接口)。但是mock A服务本身可能也比较麻烦,涉及到网络IO,端口占用等等。所以进一步的,我们只需把与服务A的交互封装到一个interface
中。这样只需要mock这个interface
就可以了。
2.2 示例
mock最常见的场景是用于单元测试
完整示例
biz.go
type People interface {
Say(s string) string
}
// 业务逻辑
func BizLogic(p People, s string) string {
return "People Say:" + p.Say(s)
}
在单元测试中,验证我们的业务逻辑
biz_test.go
import (
"github.com/stretchr/testify/mock"
"testing"
)
type FakePeople struct {
mock.Mock
}
func (m *FakePeople) Say(str string) string {
args := m.Called(str)
return args.String(0)
}
func TestSomething(t *testing.T) {
// create an instance of our test object
testObj := new(FakePeople)
// setup expectations
testObj.On("Say", "Jack").Return("hello Jack")
testObj.On("Say", "Lucy").Return("hello Lucy")
// call the code we are testing
expected := "People Say:hello Jack"
got := BizLogic(testObj, "Jack")
if expected == got {
t.Logf("got = %v; expected = %v", got, expected)
} else {
t.Errorf("got = %v; expected = %v", got, expected)
}
}
2.3 实现原理
FakePeople
是一个实现了接口People
的类。有时候它也被称为Stub
。它可以被理解为一个占位符,替代对真实的服务交互过程。
我们为针对它的请求预设了返回结果
每一组 请求+return 在stretchr/testify
中被称为call
type Call struct {
Parent *Mock
// The name of the method that was or will be called.
Method string
// Holds the arguments of the method.
Arguments Arguments
// Holds the arguments that should be returned when
// this method is called.
ReturnArguments Arguments
...
ExpectedCalls
methodName | methodArguments | ReturnArguments |
---|---|---|
"Say" | ["Jack"] | ["hello Jack"] |
"Say" | ["Lucy"] | ["hello Lucy"] |
当执行
p.Say(s)
会在预设的ExpectedCalls
中进行查找,看是否有匹配的call
,有就返回对应的ReturnArguments
, 否则会抛出异常。
3. 三种常见的mock库
3.1 仓库
库 | 备注 |
---|---|
golang/mock | golang官方出品 |
stretchr/testify | |
agiledragon/gomonkey |
3.2 支持范围
library | interface | function | member method | function variable |
---|---|---|---|---|
golang/mock | ✅ | |||
stretchr/testify | ✅ | |||
agiledragon/gomonkey | ✅ | ✅ | ✅ | ✅ |
3.3 小结
其实从实现上讲golang/mock和stretchr/testify属于同一类,都只支持interface
。
golang/mock相比stretchr/testify功能更强大,提供mockgen
工具可以针对interface
通过反射自动生成stub
。对应 2.2情况,它可以自动生成实现接口People
的类FakePeople
。
agiledragon/gomonkey是在编译阶段替换了符号表中符号对应的地址,因此它的支持范围更大。
后记
针对redis的单元测试可以使用
alicebob/miniredis