前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言单元测试

Go语言单元测试

原创
作者头像
有财君
修改2023-03-24 08:33:26
6600
修改2023-03-24 08:33:26
举报
文章被收录于专栏:我的编码学习笔记

学习Golang的时候遇到了一些单元测试问题,发现有些工具是真的好用,就记录在此,主要包括monkey、convey,还有数据库Mock等。

1. monkey打桩测试

最近遇到一种编码场景,我需要对一个库函数进行测试,但是这个函数的调用可能会影响现网数据,因此需要做一点欺骗。

monkey就是一种常见的单元测试打桩测试工具,给我的感觉有点像Java的动态代理AOP,直接将函数在运行时注入,实现动态的函数,使得目标函数或者方法逻辑跳转到桩实现上。

下面的代码是这样一种场景,我在计算KPI的时候,相关的函数CalcKPI还没有写好,所以我只能用monkey打桩:

代码语言:go
复制
package monkey

import "fmt"

func CalcKPI(name string) {
	goodAtGolang := IsGoodAtGolang(name)
	if goodAtGolang {
		fmt.Printf("KPI Level A!")
	} else {
		fmt.Println("KPI Level C")
	}
}

下面是单元测试代码:

代码语言:go
复制
package monkey

import (
	"testing"

	"bou.ke/monkey"
)

func TestCalcKPI(t *testing.T) {
	monkey.Patch(IsGoodAtGolang, func(string) bool {
		return true
	})

	CalcKPI("lyon")
}

使用起来很简单,相当于用闭包写了个伪代码,将逻辑设置成永真,那么测试结果简单可见:

只是注意要在执行命令的时候加上“-gcflags=-l”的选项,以免出现内联优化:go test -run=TestMyFunc -v -gcflags=-l

如果不加上面的选项,那么很有可能monkey桩是不生效的,这是因为编译器对比较简单的函数,在编译的时候,会将其直接内嵌进去。

当然大部分情况下我们还是用方法多于函数,所以monkey也是支持方法的打桩,对上面的例子稍加改造,首先是没有实现的方法:

代码语言:go
复制
package monkey

type Employee struct {
	Name        string
	CommitLines int
}

func newEmployee(name string, commitLines int) *Employee {
	return &Employee{Name: name, CommitLines: commitLines}
}

func (e *Employee) IsGoodAtGolang() bool {
	// 未实现的逻辑
	return false
}

接下来是HRBP逻辑:

代码语言:go
复制
package monkey

import "fmt"

func CalcKPI(name string, commitLines int) {

	r := newEmployee(name, commitLines)
	b := r.IsGoodAtGolang()
	if b {
		fmt.Printf("KPI Level A!")
	} else {
		fmt.Println("KPI Level C")
	}
}

由于没有写完的逻辑会导致这段代码的输出永远为C,因此测试代码打桩:

代码语言:go
复制
package monkey

import (
	"reflect"
	"testing"

	"bou.ke/monkey"
)

func TestCalcKPI(t *testing.T) {
	u := &Employee{Name: "lyon", CommitLines: 100}
	
	monkey.PatchInstanceMethod(reflect.TypeOf(u), "IsGoodAtGolang", func(*Employee) bool {
		return true
	})

	CalcKPI(u.Name, u.CommitLines)
}

上面只是一种很简单的应用。但是monkey的github上举的例子也很简单,基本上是满足日常使用了。

2 Convey单元测试工具

在用Java的时候,单元测试里经常会用到断言Assert工具,JUnit工具就提供了这种支持,Spring框架也支持。

但是在最开始使用Go测试框架的时候发现没有断言这种东西,感觉不可思议,没有断言怎么能成为单元测试。

goconvey工具就提供了很好用的单元测试断言支持。

代码语言:shell
复制
go get github.com/smartystreets/goconvey/convey@v1.7.2

还是利用上面的例子,将convey和monkey结合起来使用,改造一下上面的例子,将KPI的返回从void变成string:

代码语言:go
复制
package monkey

func CalcKPI(name string, commitLines int) string {

	r := newEmployee(name, commitLines)
	b := r.IsGoodAtGolang()
	if b {
		return "A"
	} else {
		return "C"
	}
}

单元测试代码用convey做一下改造:

代码语言:go
复制
package monkey

import (
	"reflect"
	"testing"

	"bou.ke/monkey"
	. "github.com/smartystreets/goconvey/convey"
)

func TestCalcKPI(t *testing.T) {
	
	Convey("简单的测试", t, func() {
		u := &Employee{Name: "lyon", CommitLines: 100}
	
		monkey.PatchInstanceMethod(reflect.TypeOf(u), "IsGoodAtGolang", func(*Employee) bool {
			return true
		})
	
		k := CalcKPI(u.Name, u.CommitLines)
		So(k, ShouldEqual, "A")
	})
}

这里就利用convey编写了一个测试单元,这个单元里可以写各种各样的逻辑,形成一个闭环,并用断言工具So进行判断。

结果输出个人感觉很好看,还有颜色渲染。

至于这个工具的高级用法,那可能就是嵌套了,convey包裹的对象是可以嵌套的。所有的断言方法都可以在官方github查询到。

还有WebUI,提供了很多强大的可视化功能,但是我暂时没发现用WebUI测试的时候如何跳过内联优化。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. monkey打桩测试
  • 2 Convey单元测试工具
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档