Go语言Mock测试 | 青训营笔记

88 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 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 提供了两种模式:

  1. source: 根据接口定义文件来生成 mock 实现
mockgen -source=foo.go [other options] 
  1. 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命令即可开始进行测试。