这是我参与「第五届青训营」伴学笔记创作活动的第 4 天。
今天就Go语言中的mock测试进行学习。
这里主要学习一下go官方的mock框架,golang/mock:GoMock 是 Go 编程语言的模拟框架。 (github.com)。网上教程很多,但是感觉都比较混乱,主要是代码自动生成工具mockgen在使用时会报一堆错误,解析 Golang 测试(2)- gomock - 掘金 (juejin.cn)写的相对详细。
此外比较出名的mock框架还有bouk/monkey: Monkey patching in Go (github.com)。
概念
在我们日常测试中,会遇到如依赖的服务或接口还没有开发好的问题,为了验证当前模块是否工作正常,我们需要模拟出还没开发好的接口。使用mock框架可以很好的帮助我们处理外部依赖,我们只需要关注自己的部分。
mockgen
Go 1.16+ 安装
go install github.com/golang/mock/mockgen
两种模式
mockgen
提供了两种模式:
- source: 根据接口定义文件来生成 mock 实现
mockgen -source=foo.go [other options]
- reflect:通过反射生成 mock 实现,我们需要传入 import 路径,以及用逗号分隔的一系列接口
mockgen database/sql/driver Conn,Driver
两种模式并没有本质差异,根据你的场景选择即可。
常用选项
-source
: 设置你需要生成mock实现的接口文件;-destination
: 设置mock实现将要生成到的地址,若未设置,将会打印到标准输出;-package
: 设置生成的mock文件的包名,如果不设置,默认会采用 mock_ 前缀加上文件名。
测试
需要注意一点,能够通过mock框架自动生成代码的,必须定义好接口!
目录如下,其中可以不太关注main.go以及go.mod:
├──gotest
├── mock
├── person
│ └── male.go
└── user
│ ├── user.go
│ └── user_test.go
├── main.go
└── go.mod
在 person/male.go 中定义一个 Male 的接口:
package person
type Male interface {
Get(id int64) error
}
在user/user.go 中,填充 User 相关逻辑:
package user
import "gotest/person"
type User struct {
Person person.Male
}
func NewUser(p person.Male) *User {
return &User{Person: p}
}
func (u *User) GetUserInfo(id int64) error {
return u.Person.Get(id)
}
回到项目根目录下,执行 mockgen 命令
mockgen -source ./person/male.go -destination ./mock/male_mock.go -package=mock
执行完毕后,你会发现 mock 目录下多了一个 male_mock.go 文件,这就是 mockgen 根据我们的 Male
接口生成的 mock 实现。
接下来写测试函数,在 user/user_test.go 里面实现:
package user
import (
"gotest/mock"
"testing"
"github.com/golang/mock/gomock"
)
func TestUser_GetUserInfo(t *testing.T) {
ctl := gomock.NewController(t)
defer ctl.Finish()
var id int64 = 1
mockMale := mock.NewMockMale(ctl)
gomock.InOrder(
mockMale.EXPECT().Get(id).Return(nil),
)
user := NewUser(mockMale)
err := user.GetUserInfo(id)
if err != nil {
t.Errorf("user.GetUserInfo err: %v", err)
}
}
最后执行go test命令即可开始进行测试。