go test 测试单个文件和测试单个函数

  1. 测试单个文件,一定要带上被测试的原文件

    go test -v wechat_test.go wechat.go

  2. 测试单个方法

    go test -v -test.run TestRefreshAccessToken

go 单元测试写法
参考 https://studygolang.com/articles/22982

testing
go语言package提供的自动化测试框架,
testing支持普通用例测试、压力测试、并行测试,基本能满足单测需求;

缺失:

testing不支持mock数据,想要mock数据必须自己实现mock逻辑,这会增加许多不必要的工作量。

mock的重要性
理想情况下,一个好的函数结构必须有入参、出参,完成的是一项单一、独立的工作,比如:

func add(a int, b int) int {
return a + b
}
这样的函数写单测很简单,且轻易就能达到100%覆盖率。

但实际工作中,这样纯粹的函数占比可能不到10%,单个函数往往不是独立的,它需要依赖于其他模块、三方库、数据库等等。

以上传图片为例,上传一张图片样本函数:

func uploadImage(content []byte, UID string, fdfs *tsFDFS) error {
// 1. 上传图片到fdfs
url := fdfs.Upload(content)
// 2. 生成缩略图
resize.Resize(…)
jpeg.Encode(…)
// 3. 图片入库
sample := &database.yangbenModel{ … }
database.CreateSample(…)
// 4. 图片绑定任务
binding := &database.ExamplennotationTask{ … }
database.CreateBinding(…)
return nil
}
如果在单测中想要正常走完这个函数且不出错,我们需要有一个真实的fdfs环境可以上传数据成功,一个真实的数据库,且根据业务逻辑,我们想要插入一个sample前,必须有对应的enterprise、pipeline、annotation-task等等;

于是,在此前,项目中使用testing的单测实现思路是这样的:

func TestUploadImage(t *testing.T) {
// 1. 创建真实的fdfs环境
fdfs := &FDFS{ … }
// 2. 连接真实的数据库
db := database.NewGormConn(…)
// 3. 插入一条enters数据
enters := &database.EnterpriseModel{…}
database.CreateEnters(…)
// 4. 插入一条业务数据

// 5. 插入另外一条业务数据

// 6. 开始执行单测
uploadImage(…)

}
可以看到,单测之前进行了大量耗时的、冗余的、无意义的工作

单测执行耗时长,正常一条单测时间一般在100ms内,在模拟了真实场景后,单测时间大幅增加,甚至项目中有部分单测超过1分钟;
单测编码效率低,需要了解了业务场景后,才能编写完一条单测case;
过于依赖真实环境,稳定性差,维护成本高,对于一些无法模拟真实环境的流程,只能放弃覆盖测试。
mock框架
gomonkey 单元测试
安装

go get -u -v https://github.com/agiledragon/gomonkey

github地址为:https://github.com/agiledragon/gomonkey
参考博客: https://studygolang.com/articles/15034
目前自己尝试过mock方法 把代码使用的粘贴供gopher参考下
这个地方是rpc调用其他服务,
测试中用打桩的方式,将这个
函数的结果先执行了,当执行
这个函数时,采用这个函数
打桩时mock的数据就可以了

在这里插入图片描述
在这里插入图片描述
测试文件中如何写mock第三方数据呢?
ApplyMethod 第三个参数
func() 中的第一个参数为这个
方法属于那个类型,剩余的参数
书写方式为 func(_ 绑定的那个类型,
,_ type)
例如
func(_ 绑定的那个类型,
,_ string, _ int)(返回结果)

在这里插入图片描述

gostub
对全局变量、函数或过程打桩,对代码中的外部依赖进行劫持并替换成mock的内容

为一个全局变量打桩
stubs := gostub.Stub(&num, 10)
defer stubs.Reset()
为一个函数打桩
stubs := gostub.StubFunc(&Func, func(args string) error {
return nil
})
defer stubs.Reset()
为一个过程打桩
stubs := gostub.StubFunc(&Destroy)
defer stubs.Reset()
场景组合
以上文测试上传一张图片样本为例

func TestUploadImage(t *testing.T) {
// 1. stub fdfs
stubs := gostub.StubFunc(&Upload, func() string {
return “”
})
defer stubs.Reset()

// 2. stub 生成缩略图
stubs = gostub.StubFunc(&resize.Resize, func() error {
	return nil
})
// 3. stub sample create
stubs = gostub.StubFunc(&database.CreateSample, func() error {
	return nil
})
...
// 4. stub binding create
...
// 5. 开始执行单测
uploadImage(...)
...

}
缺点
对代码有一定的侵入性 (需要将函数改为全局变量语法形式、对三方库需要做一层包装)
无法对方法(成员函数)进行打桩
monkey
monkey是go的一个猴子补丁(monkeypatching)框架,在运行时通过汇编语句重写可执行文件,将待打桩函数或方法的实现跳转到桩实现,原理和热补丁类似。

通过monkey可以解决stub无法为方法打桩的问题,但monkey不是线程安全的,不能用于并发测试。

为一个函数打桩
guard := monkey.Patch(Func, func(args string) error {
return nil
})

defer guard.Unpatch()
为一个方法打桩
guard := monkey.PatchInstanceMethod(reflect.TypeOf(client), “Test”, func(args string) error {
return nil
})

defer guard.Unpatch()
缺点
线程不安全
在macOS 10.15及以上版本无法运行,由于其原理是修改可执行文件,从Catalina版本起,系统对文件读写权限做了更严格的管理,monkey修改的文件无写权限,运行panic,参考https://github.com/agiledragon/gomonkey/issues/10

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
测试 Go 中的单个方法,您可以按照以下步骤进行操作: 1. 创建测试文件 在与要测试的 Go 文件相同的目录中创建一个名为 `<filename>_test.go` 的文件,其中 `<filename>` 是要测试文件的名称。例如,如果要测试名为 `calculator.go` 的文件中的 `Add` 方法,则测试文件应命名为 `calculator_test.go`。 2. 导入测试所需的包 在测试文件的顶部,导入任何需要在测试中使用的包。例如,如果要测试 `Add` 方法,可能需要导入 `testing` 包和 `calculator` 包。 3. 创建测试函数测试文件中,创建一个名为 `Test<FunctionName>` 的函数,其中 `<FunctionName>` 是要测试函数的名称。例如,如果要测试 `Add` 方法,则测试函数应命名为 `TestAdd`。 4. 写测试代码 在测试函数中,编写测试代码以测试测试的方法。例如,如果要测试 `Add` 方法,您可以编写代码来调用该方法并检查其返回值是否与预期值相同。 5. 运行测试 在终端中,使用 `go test` 命令运行测试。Go 将运行测试函数并返回测试结果。 下面是一个简单的示例测试函数的代码: ```go package calculator import "testing" func TestAdd(t *testing.T) { result := Add(2, 3) if result != 5 { t.Errorf("Add(2, 3) = %d; expected 5", result) } } ``` 在此示例中,测试函数 `TestAdd` 调用 `Add` 方法并检查其返回值是否为预期值。如果返回值与预期值不同,则测试将失败,并且 `t.Errorf` 函数将输出一条错误消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值