go test 下篇
前言
go test 上篇 给大家介绍了golang自带的测试框架,包括单元测试和性能测试。但是在实际生产中测试经常会遇到一些网络或者依赖的第三方系统接口,运行测试用例的时候希望忽略这些接口的实际依赖,聚焦在具体业务逻辑代码,这就需要模拟这些接口的行为,也就是我今天介绍给大家的golang/mock,一个golang的mock框架。
演示环境
$ uname -a
Darwin 18.6. Darwin Kernel Version 18.6.: Thu Apr :: PDT ; root:xnu-4903.261.~/RELEASE_X86_64 x86_64
$ go version
go version go1.12.4 darwin/amd64
安装
go get github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen
用法
1.定义我们需要mock的接口。如:
type MyInterface interface {
SomeMethod(x int64, y string)
}
2.使用mockgen命令生成接口的mock文件。
mockgen -package example_test -destination example_mock.go
3.在测试中使用mock接口:
func TestMyThing(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockObj := something.NewMockMyInterface(mockCtrl)
mockObj.EXPECT().SomeMethod(, "blah")
// pass mockObj to a real object and play with it.
}
接口说明
以官方提供的https://github.com/golang/mock/blob/master/sample/user_test.go文件作为示例说明:
func TestRemember(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex.EXPECT().Put("a", ) // literals work
mockIndex.EXPECT().Put("b", gomock.Eq()) // matchers work too
// NillableRet returns error. Not declaring it should result in a nil return.
mockIndex.EXPECT().NillableRet()
// Calls that returns something assignable to the return type.
boolc := make(chan bool)
// In this case, "chan bool" is assignable to "chan<- bool".
mockIndex.EXPECT().ConcreteRet().Return(boolc)
// In this case, nil is assignable to "chan<- bool".
mockIndex.EXPECT().ConcreteRet().Return(nil)
// Should be able to place expectations on variadic methods.
mockIndex.EXPECT().Ellip("%d", , , , , ) // direct args
tri := []interface{}{, , , , }
mockIndex.EXPECT().Ellip("%d", tri...) // args from slice
mockIndex.EXPECT().EllipOnly(gomock.Eq("arg"))
user.Remember(mockIndex, []string{"a", "b"}, []interface{}{, })
// Check the ConcreteRet calls.
if c := mockIndex.ConcreteRet(); c != boolc {
t.Errorf("ConcreteRet: got %v, want %v", c, boolc)
}
if c := mockIndex.ConcreteRet(); c != nil {
t.Errorf("ConcreteRet: got %v, want nil", c)
}
// Try one with an action.
calledString := ""
mockIndex.EXPECT().Put(gomock.Any(), gomock.Any()).Do(func(key string, _ interface{}) {
calledString = key
})
mockIndex.EXPECT().NillableRet()
user.Remember(mockIndex, []string{"blah"}, []interface{}{})
if calledString != "blah" {
t.Fatalf(`Uh oh. %q != "blah"`, calledString)
}
// Use Do with a nil arg.
mockIndex.EXPECT().Put("nil-key", gomock.Any()).Do(func(key string, value interface{}) {
if value != nil {
t.Errorf("Put did not pass through nil; got %v", value)
}
})
mockIndex.EXPECT().NillableRet()
user.Remember(mockIndex, []string{"nil-key"}, []interface{}{nil})
}
- EXPECT 表示期望在后续的测试代码中会用到,且一定要用到,否则会报错。例如第6行的Put("a", 1)方法会在第24行的Remeber函数里面调用。
- Return 表示mock接口的返回值,例如第14行的ConcreteRet()函数返回boolc。
- Do 表示当匹配到对应的函数时执行对应的行为。例如第35行,当匹配到put(gomock.Any(), gomock.Any())时执行func(key string, _ interface{}),如果函数需要返回值用DoAndReturn函数。
- Any 表示构造一个一直会match的matcher。
上述示例使用了Index接口的mock方法。第6,7,10,14,16,19,21,22定义的EXPECT行为会在第24行的Remeber函数中被调用:
user.Remember(mockIndex, []string{"a", "b"}, []interface{}{, })
func Remember(index Index, keys []string, values []interface{}) {
for i, k := range keys {
index.Put(k, values[i])
}
err := index.NillableRet()
if err != nil {
log.Fatalf("Woah! %v", err)
}
if len(keys) > && keys[] == "a" {
index.Ellip("%d", , , , , )
index.Ellip("%d", , , , , )
index.EllipOnly("arg")
}
}
mock接口文件完成后运行测试:
$ git clone https://github.com/golang/mock
Cloning into 'mock'...
remote: Enumerating objects: , done.
remote: Counting objects: % (/), done.
remote: Compressing objects: % (/), done.
remote: Total (delta ), reused (delta ), pack-reused
Receiving objects: % (/), 450.07 KiB | 354.00 KiB/s, done.
Resolving deltas: % (/), done.
$ cd mock/sample/
$ go test -v
=== RUN TestRemember
--- PASS: TestRemember (.00s)
=== RUN TestVariadicFunction
--- PASS: TestVariadicFunction (.00s)
=== RUN TestGrabPointer
--- PASS: TestGrabPointer (.00s)
=== RUN TestEmbeddedInterface
--- PASS: TestEmbeddedInterface (.00s)
=== RUN TestExpectTrueNil
--- PASS: TestExpectTrueNil (.00s)
PASS
ok github.com/golang/mock/sample .017s
在实际生产中经常将需要mock的接口对象定义为一个全局变量,然后在测试用例中用mock对象替换这个对象,替换的方法可以直接替换,也可以用goStub第三方优雅替换。
var configFile = "config.json"
func GetConfig() ([]byte, error) {
return ioutil.ReadFile(configFile)
}
// Test code
stubs := gostub.Stub(&configFile, "/tmp/test.config")
data, err := GetConfig()
// data will now return contents of the /tmp/test.config file
总结
文章具体介绍了gomock库的使用场景和具体用法,作为go test官方测试框架的一个补充。gomock在生产代码中会被经常用到,当然也有其他的golang mock第三方开源库,例如testify。具体的选择需要根据大家的需求具体分析。
go test 下篇的更多相关文章
- Asp.Net WebApi核心对象解析(下篇)
在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- LabVIEW 吸星大法 - 看见的好东西都是我的(下篇)
前言 写了多年的LabVIEW程序,你是否面临这样的问题 总是在做一些重复的工作,感觉很没有意思: 总在不停的写代码,做类似的控件,实现相同的功能,丝毫没有成就感: 总在天加班,没有时间去提高自己; ...
- TaintDroid剖析之DVM变量级污点跟踪(下篇)
TaintDroid剖析之DVM变量级污点跟踪(下篇)作者:简行.走位@阿里聚安全 1 回顾 在上一章节中我们详细分析了TaintDroid对DVM方法参数和方法变量的变量级污点跟踪机制,现在我们 ...
- ASP.NET Core的配置(4):多样性的配置来源[下篇]
我们在上篇和中篇对配置模型中默认提供的各种ConfigurationProvider进行了深入详尽的介绍,如果它们依然不能满足项目中的配置需求,我们可以还可以通过自定义ConfigurationPro ...
- ASP.NET Core的配置(3): 将配置绑定为对象[下篇]
我们在<读取配置信息>通过实例的形式演示了如何利用Options模型以依赖注入的方式直接获取由指定配置节绑定生成的Options对象,我们再次回顾一下当初我们编写的程序.如下面的代码片段所 ...
- 谈谈基于OAuth 2.0的第三方认证 [下篇]
从安全的角度来讲,<中篇>介绍的Implicit类型的Authorization Grant存在这样的两个问题:其一,授权服务器没有对客户端应用进行认证,因为获取Access Token的 ...
- Sass-也许你想和CSS玩耍起来(下篇)
问心无愧,共勉! sass-也许你想和CSS玩耍起来(上篇) 上篇中主要介绍了一些sass的基本特性.下篇中,主要是写一些我们常用的sass控制命令,函数和规则. sass进阶 控制命令 可能看过上篇 ...
- MS SQL统计信息浅析下篇
MS SQL统计信息浅析上篇对SQL SERVER 数据库统计信息做了一个整体的介绍,随着我对数据库统计信息的不断认识.理解,于是有了MS SQL统计信息浅析下篇. 下面是我对SQL Serve ...
- 那些年我们写过的T-SQL(下篇)
下篇的内容很多都会在工作中用到,尤其是可编程对象,那些年我们写过的存储过程,有木有?到目前为止很多大型传统企业仍然很依赖存储过程.这部分主要难理解的部分是事务和锁机制这块,本文会进行简单的阐述.虽然很 ...
随机推荐
- eclipse主题样式
Eclipse Color Themeshttp://eclipsecolorthemes.org/ Get it Download from Eclipse Marketplace Install ...
- 无法启动Visual Studio的localhost web服务器,端口"xxxx"已被使用
解决方法:项目属性-Web里面有web服务器端口的设置,换个端口即可.项目属性->web->服务器,不要选择“自动分配端口”,选择“使用指定端口”,后面输入一个端口号
- Oracle 索引(转)
一.索引介绍 1.1 索引的创建语法: CREATE UNIUQE | BITMAP INDEX <schema>.<index_name> ON <schema> ...
- 大话Spark(4)-一文理解MapReduce Shuffle和Spark Shuffle
Shuffle本意是 混洗, 洗牌的意思, 在MapReduce过程中需要各节点上同一类数据汇集到某一节点进行计算,把这些分布在不同节点的数据按照一定的规则聚集到一起的过程成为Shuffle. 在Ha ...
- slam学习足迹
1.slam入门介绍 2.齐次坐标系 3.贝叶斯滤波 均值:平均值 标准差:样本的集中程度/分散度 方差:标准差的平方 协方差:不同维度之间的关系(相关度) 协方差矩阵:多维度之间的关系(相关度) 4 ...
- SQLite添加列的限制
SQLite添加列的限制 向SQLite表中添加字段,需要注意以下问题: (1)添加的列不能定义为主键. (2)添加的列为日期时间类型,不能使用CURRENT_TIME.CURRENT_DATE. ...
- luogu P1854 花店橱窗布置
题目描述 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按1到V顺序编号,V是花瓶的数目.花束可以移动,并且每束花用1到F的整数标识 ...
- 解决每次启动Office都出出现设置向导的问题
昨天不知道怎么地,每次打开Excel都会出现"正在配置Office"的设置向导,并且修复.重置用户均无法解决. 在网上搜索了一下,找到了一个解决方法:把"C:\Progr ...
- java visual VM使用简介
转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/44999175 作者:小马 VisualVM 是一款免费的性能分析工具.它通过 jv ...
- 安装 Groovy
brew install groovy http://wiki.jikexueyuan.com/project/groovy-introduction/install-groovy.html