We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
转载自:https://www.liwenzhou.com/posts/Go/golang-unit-test-3/ 示例代码原作者已上传至Github,点击👉🏻https://github.com/Q1mi/golang-unit-test-demo 查看完整源代码。
这是Go语言单元测试从零到溜系列教程的第5篇,介绍了如何在单元测试中使用monkey进行打桩。
在上一篇《Go单元测试--Mock接口实现和对接口打桩》中,我们介绍了如何在单元测试中使用gomock和gostub工具mock接口及打桩。
gomock
gostub
在这一篇中我们将介绍一个更强大的打桩工具——monkey,它支持为任意函数及方法进行打桩。
monkey
monkey是一个Go单元测试中十分常用的打桩工具,它在运行时通过汇编语言重写可执行文件,将目标函数或方法的实现跳转到桩实现,其原理类似于热补丁。
monkey库很强大,但是使用时需注意以下事项:
-gcflags=-l
go get bou.ke/monkey
假设你们公司中台提供了一个用户中心的库varys,使用这个库可以很方便的根据uid获取用户相关信息。但是当你编写代码的时候这个库还没实现,或者这个库要经过内网请求但你现在没这能力,这个时候要为MyFunc编写单元测试,就需要做一些mock工作。
varys
MyFunc
// func.go func MyFunc(uid int64)string{ u, err := varys.GetInfoByUID(uid) if err != nil { return "welcome" } // 这里是一些逻辑代码... return fmt.Sprintf("hello %s\n", u.Name) }
我们使用monkey库对varys.GetInfoByUID进行打桩。
varys.GetInfoByUID
// func_test.go func TestMyFunc(t *testing.T) { // 对 varys.GetInfoByUID 进行打桩 // 无论传入的uid是多少,都返回 &varys.UserInfo{Name: "liwenzhou"}, nil monkey.Patch(varys.GetInfoByUID, func(int64)(*varys.UserInfo, error) { return &varys.UserInfo{Name: "liwenzhou"}, nil }) ret := MyFunc(123) if !strings.Contains(ret, "liwenzhou"){ t.Fatal() } }
执行单元测试:
注意:这里为防止内联优化添加了-gcflags=-l参数。
go test -run=TestMyFunc -v -gcflags=-l
输出:
=== RUN TestMyFunc --- PASS: TestMyFunc (0.00s) PASS ok monkey_demo 0.009s
除了对函数进行mock外monkey也支持对方法进行mock。
// method.go type User struct { Name string Birthday string } // CalcAge 计算用户年龄 func (u *User) CalcAge() int { t, err := time.Parse("2006-01-02", u.Birthday) if err != nil { return -1 } return int(time.Now().Sub(t).Hours()/24.0)/365 } // GetInfo 获取用户相关信息 func (u *User) GetInfo()string{ age := u.CalcAge() if age <= 0 { return fmt.Sprintf("%s很神秘,我们还不了解ta。", u.Name) } return fmt.Sprintf("%s今年%d岁了,ta是我们的朋友。", u.Name, age) }
如果我们为GetInfo编写单元测试的时候CalcAge方法的功能还未完成,这个时候我们可以使用monkey进行打桩。
GetInfo
CalcAge
// method_test.go func TestUser_GetInfo(t *testing.T) { var u = &User{ Name: "q1mi", Birthday: "1990-12-20", } // 为对象方法打桩 monkey.PatchInstanceMethod(reflect.TypeOf(u), "CalcAge", func(*User)int { return 18 }) ret := u.GetInfo() // 内部调用u.CalcAge方法时会返回18 if !strings.Contains(ret, "朋友"){ t.Fatal() } }
❯ go test -run=User -v === RUN TestUser_GetInfo --- PASS: TestUser_GetInfo (0.00s) PASS ok monkey_demo 0.012s
monkey基本上能满足我们在单元测试中打桩的任何需求。
社区中还有一个参考monkey库实现的gomonkey库,原理和使用过程基本相似,这里就不再啰嗦了。除此之外社区里还有一些其他打桩工具如GoStub(上一篇介绍过为全局变量打桩)等。
熟练使用各种打桩工具能够让我们更快速地编写合格的单元测试,为我们的软件保驾护航。
本文通过外部函数依赖及内部方法依赖两个示例,介绍了如何使用monkey对依赖的函数和方法进行打桩。
在下一篇中,我们将介绍编写单元测试时常用的工具——goconvey。
goconvey
前文推荐
Go单元测试基础
Go数据库 CRUD 的 Mock 测试
Go模拟服务请求和接口返回
Go Mock接口实现和对接口打桩
The text was updated successfully, but these errors were encountered:
No branches or pull requests
这是Go语言单元测试从零到溜系列教程的第5篇,介绍了如何在单元测试中使用monkey进行打桩。
在上一篇《Go单元测试--Mock接口实现和对接口打桩》中,我们介绍了如何在单元测试中使用
gomock
和gostub
工具mock接口及打桩。在这一篇中我们将介绍一个更强大的打桩工具——
monkey
,它支持为任意函数及方法进行打桩。monkey
介绍
monkey是一个Go单元测试中十分常用的打桩工具,它在运行时通过汇编语言重写可执行文件,将目标函数或方法的实现跳转到桩实现,其原理类似于热补丁。
monkey库很强大,但是使用时需注意以下事项:
-gcflags=-l
关闭Go语言的内联优化。安装
使用示例
假设你们公司中台提供了一个用户中心的库
varys
,使用这个库可以很方便的根据uid获取用户相关信息。但是当你编写代码的时候这个库还没实现,或者这个库要经过内网请求但你现在没这能力,这个时候要为MyFunc
编写单元测试,就需要做一些mock工作。我们使用
monkey
库对varys.GetInfoByUID
进行打桩。执行单元测试:
输出:
除了对函数进行mock外
monkey
也支持对方法进行mock。如果我们为
GetInfo
编写单元测试的时候CalcAge
方法的功能还未完成,这个时候我们可以使用monkey进行打桩。执行单元测试:
monkey
基本上能满足我们在单元测试中打桩的任何需求。社区中还有一个参考monkey库实现的gomonkey库,原理和使用过程基本相似,这里就不再啰嗦了。除此之外社区里还有一些其他打桩工具如GoStub(上一篇介绍过为全局变量打桩)等。
熟练使用各种打桩工具能够让我们更快速地编写合格的单元测试,为我们的软件保驾护航。
总结
本文通过外部函数依赖及内部方法依赖两个示例,介绍了如何使用
monkey
对依赖的函数和方法进行打桩。在下一篇中,我们将介绍编写单元测试时常用的工具——
goconvey
。前文推荐
Go单元测试基础
Go数据库 CRUD 的 Mock 测试
Go模拟服务请求和接口返回
Go Mock接口实现和对接口打桩
The text was updated successfully, but these errors were encountered: