Golang单元测试利器:gomock工具详解
发表时间: 2024-07-01 22:51
在做单测时为了解耦相关依赖,需要mock工具,这里推荐第三方库:
https://github.com/golang/mock
https://github.com/uber-go/mock
目前golang/mock库停止维护,由其分支uber-go/mock继续维护,用法相同。
安装命令
go install go.uber.org/mock/mockgen@latest
查看mockgen工具版本
mockgen -version
输出:v0.4.0
mockgen
可以查看相关命令
mockgen has two modes of operation: source and reflect.Source mode generates mock interfaces from a source file.It is enabled by using the -source flag. Other flags thatmay be useful in this mode are -imports and -aux_files.Example: mockgen -source=foo.go [other options]Reflect mode generates mock interfaces by building a programthat uses reflection to understand interfaces. It is enabledby passing two non-flag arguments: an import path, and acomma-separated list of symbols.Example: mockgen database/sql/driver Conn,Driver -aux_files string (source mode) Comma-separated pkg=path pairs of auxiliary Go source files. -build_flags string (reflect mode) Additional flags for go build. -copyright_file string Copyright file used to add copyright header -debug_parser Print out parser results only. -destination string Output file; defaults to stdout. -exclude_interfaces string Comma-separated names of interfaces to be excluded -exec_only string (reflect mode) If set, execute this reflection program. -imports string (source mode) Comma-separated name=path pairs of explicit imports to use. -mock_names string Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix. -package string Package of the generated code; defaults to the package of the input with a 'mock_' prefix. -prog_only (reflect mode) Only generate the reflection program; write it to stdout and exit. -self_package string The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude. -source string (source mode) Input Go source file; enables source mode. -typed Generate Type-safe 'Return', 'Do', 'DoAndReturn' function -version Print version. -write_generate_directive Add //go:generate directive to regenerate the mock -write_package_comment Writes package documentation comment (godoc) if true. (default true) -write_source_comment Writes original file (source mode) or interface names (reflect mode) comment if true. (default true)
mockgen支持两种模式:源文件和反射
1、Source mode
通过源文件生成mock接口
示例
mockgen -source=foo.go [other options]
2、Reflect mode
反射模式通过构建一个使用反射来理解接口的程序来生成mock接口。
示例
mockgen database/sql/driver Conn,Driver
新建测试目录db,文件db.go、db_getter.go
db.go
package dbtype DBInterface interface { Get(val string) string}type DB struct {}func (d *DB) Get(val string) string { return val}
db_getter.go
package dbfunc GetFromDB(db DB) string { return db.Get("example")}
使用mockgen工具对所需mock的interface生成mock文件
在db目录下执行
mockgen -source ./db.go -destination ./mock/db_mock.go
在db/mode目录下生成db_mock.go
// Code generated by MockGen. DO NOT EDIT.// Source: ./db.go//// Generated by this command://// mockgen -source ./db.go -destination ./mock/db_mock.go//// Package mock_db is a generated GoMock package.package mock_dbimport ( reflect "reflect" gomock "go.uber.org/mock/gomock")// MockDBInterface is a mock of DBInterface interface.type MockDBInterface struct { ctrl *gomock.Controller recorder *MockDBInterfaceMockRecorder}// MockDBInterfaceMockRecorder is the mock recorder for MockDBInterface.type MockDBInterfaceMockRecorder struct { mock *MockDBInterface}// NewMockDBInterface creates a new mock instance.func NewMockDBInterface(ctrl *gomock.Controller) *MockDBInterface { mock := &MockDBInterface{ctrl: ctrl} mock.recorder = &MockDBInterfaceMockRecorder{mock} return mock}// EXPECT returns an object that allows the caller to indicate expected use.func (m *MockDBInterface) EXPECT() *MockDBInterfaceMockRecorder { return m.recorder}// Get mocks base method.func (m *MockDBInterface) Get(val string) string { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Get", val) ret0, _ := ret[0].(string) return ret0}// Get indicates an expected call of Get.func (mr *MockDBInterfaceMockRecorder) Get(val any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDBInterface)(nil).Get), val)}
db_getter_test.go
package dbimport ( mock_db "demo/db/mock" "testing" "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock")func TestGetFromDB(t *testing.T) { //创建gomock顶级控制器,用来记录后续mock对象的范围,生命周期等信息,另外它是协成安全的 ctrl := gomock.NewController(t) // 延迟执行期望断言 defer ctrl.Finish() //创建一个mock实例 mockDb := mock_db.NewMockDBInterface(ctrl) //gomock.InOrder 控制执行顺序 gomock.InOrder( mockDb.EXPECT(). Get(gomock.Eq("example")). //get方法参数 Return("data"). //设置期望返回值 Times(1), //执行次数 ) got := GetFromDB(mockDb) //比较实际返回的值和预期是否相等 assert.Equal(t, "data", got)}
常用参数:
更多参数移步官方https://pkg.go.dev/github.com/golang/mock/gomock#pkg-index
执行
go test -v
结果:
=== RUN TestClear
--- PASS: TestClear (0.00s)
PASS
ok demo 0.309s