前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go测试框架gomock的使用

go测试框架gomock的使用

原创
作者头像
Johns
修改2022-06-30 10:26:45
4.1K0
修改2022-06-30 10:26:45
举报
文章被收录于专栏:代码工具代码工具

一。介绍

gomock是golang官方开发维护的接口级别的mock方案,包含了GoMock包和mockgen工具两部分,其中GoMock包完成对桩对象生命周期的管理,mockgen工具用来生成interface对应的Mock类源文件。要使用gomock的一个前提是模块之间务必通过接口进行依赖,而不是依赖具体实现,否则mock会非常困难。这个工具目前业界用的并不多,主要是局限性太大,所以我们只需要简单了解一下如何使用就行。

github地址:https://github.com/golang/mock

二。使用

1. 安装

代码语言:txt
复制
go get -u github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen

2. Quick start

第一步:定义接口,注意这个工具之支持对接口生成mock,其他的类型方法不支持。
代码语言:txt
复制
package dao

import (
	"fmt"
	_ "github.com/golang/mock/mockgen/model"
)

// 用户持久层操作对象
type UserDao interface {
	Update(id, name, phoneNumber string) int64
	Update2(param ...string) int64
	Add(name, phoneNumber string) (int64, error)
	Select(id string) int64
	Delete(id string) int64
}

type userDao struct{}

func (u userDao) Update(id, name, phoneNumber string) int64 {
	fmt.Println(id, name, phoneNumber)
	return 1
}
第二步:使用命令生成mock类
代码语言:txt
复制
mockgen  -destination mock_user_dao.go -package dao -source user_dao.go 

如果觉得命令太长了,可以直接在UserDao上面加个go:generate的注释如下

代码语言:txt
复制
package dao

import (
	"fmt"
	_ "github.com/golang/mock/mockgen/model"
)

//go:generate mockgen -destination mock_user_dao.go -package dao -source user_dao.go
// 用户持久层操作对象
type UserDao interface {
	Update(id, name, phoneNumber string) int64
	Update2(param ...string) int64
	Add(name, phoneNumber string) (int64, error)
	Select(id string) int64
	Delete(id string) int64
}
...

然后在当前包的目录下bash执行go generate也是可以生成mock文件的。

第三步:自定义mock实现并进行断言
代码语言:txt
复制
package dao

import (
	"errors"
	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"testing"
)

/**
 * @Description
 * @Author guirongguo
 * @Email 
 * @Date 2021/8/31 20:37
 **/

func Test_userDao(t *testing.T) {

	// step1. 初始化一个mock controller
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()
	mockObj := NewMockUserDao(mockCtrl)

	// step2. 定义mock的具体执行逻辑
	// 1.参数支持Eq,Any,Not,Nil
	//Eq(value) 表示与 value 等价的值。
	//Any() 可以用来表示任意的入参。
	//Not(value) 用来表示非 value 以外的值。
	//Nil() 表示 None 值
	//
	// 2.mock方法调用次数支持如下
	//Times() 断言 Mock 方法被调用的次数。
	//MaxTimes() 最大次数。
	//MinTimes() 最小次数。
	//AnyTimes() 任意次数(包括 0 次)
	//
	// 3.返回值支持
	// Return 返回确定的值
	// Do Mock 方法被调用时,要执行的操作吗,忽略返回值。
	// DoAndReturn 可以动态地控制返回值。
	c1 := mockObj.EXPECT().Update("001", "ggr", "10010").Return(int64(1))
	c2 := mockObj.EXPECT().Update("001", "ggr", gomock.Any()).Return(int64(1))
	mockObj.EXPECT().Add("", "1001").Return(int64(0), errors.New("name is invalid")).AnyTimes()
	mockObj.EXPECT().Add("1001", gomock.Not("1001")).Return(int64(0), errors.New("phone_number is invalid")).MinTimes(1)
	mockObj.EXPECT().Add(gomock.Eq("1001"), "1001").Return(int64(0), errors.New("name is empty")).Times(1)
	mockObj.EXPECT().Select(gomock.Any()).Return(int64(1)).MaxTimes(2)
	mockObj.EXPECT().Update2(gomock.Any()).Return(int64(1)).Times(2)

	mockObj.EXPECT().Delete("1001").Do(func(i string) {
		t.Log("delete id=1001")
	})

	mockObj.EXPECT().Delete(gomock.Not("1001")).DoAndReturn(func(i string) int64 {
		return int64(1)
	})

	// step3. 限制stub函数的调用顺序,如果顺序不一致,则报错
	gomock.InOrder(c1, c2)

	// step4. 测试验证
	ret1 := mockObj.Update("001", "ggr", "10010")
	ret2 := mockObj.Update("001", "ggr", "10020")
	ret3 := mockObj.Update2("1", "")
	ret4 := mockObj.Update2("")
	ret5 := mockObj.Select("")
	ret6, err1 := mockObj.Add("1001", "1001")
	ret7, err2 := mockObj.Add("1001", "1002")
	ret8 := mockObj.Delete("1001")
	ret9 := mockObj.Delete("1002")

	// step5. 断言
	assert.Equal(t, ret1, int64(1))
	assert.Equal(t, ret2, int64(1))
	assert.Equal(t, ret3, int64(1))
	assert.Equal(t, ret4, int64(1))
	assert.Equal(t, ret5, int64(1))
	assert.Equal(t, ret6, int64(0))
	assert.Equal(t, ret7, int64(0))
	assert.Equal(t, ret8, int64(0))
	assert.Equal(t, ret9, int64(1))
	assert.NotNil(t, err1)
	assert.NotEmpty(t, err2)
}

自定义mock实现主要包含了自定义参数,自定义返回值,自定义mock调用次数以及调用顺序。

(1)自定义参数

参数支持Eq,Any,Not,Nil,分别代表一下含义:

  • Eq(value) 用于参数为固定值的场景。
  • Any() 用于任意参数的场景。
  • Not(value) 用于表示参数非 value 以外的值场景。
  • Nil() 用于表示参数None 值的场景

(2)自定义返回值

返回值支持如下几种:

  • Return 用于返回确定的值的场景
  • Do 用于无返回值的场景。
  • DoAndReturn 用于可以动态地控制返回值。

(3)自定义mock调用次数

mock调用次数支持如下几种场景:

  • Times() 断言 Mock 方法被调用的次数, 指定次数。
  • MaxTimes() 最大次数。
  • MinTimes() 最小次数。
  • AnyTimes() 任意次数(包括 0 次)

(4)自定义mock调用顺序

当存在多个mock之间相互调用的情况时,可以通过一下2种方式定义mock执行的顺序:

  • 直接在函数后面接After
  • 使用gomock.InOrder设置执行顺序

更多使用方法请参考官方文档:https://pkg.go.dev/github.com/golang/mock/gomock#pkg-examples

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一。介绍
  • 二。使用
    • 1. 安装
      • 2. Quick start
        • 第一步:定义接口,注意这个工具之支持对接口生成mock,其他的类型方法不支持。
        • 第二步:使用命令生成mock类
        • 第三步:自定义mock实现并进行断言
      • (1)自定义参数
        • (2)自定义返回值
          • (3)自定义mock调用次数
            • (4)自定义mock调用顺序
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档