这是我参与「第五届青训营」伴学笔记创作活动的第 17 天
这是我参与「第五届青训营」伴学笔记创作活动的第 17 天
前言
因为项目中接到了负责测试的任务,今天的部分是在项目中的实战
本文中大量内容只是个人考量 并不代表正确做法 欢迎大家斧正
第一部分:目录结构
首先考虑进行怎么样的测试 测试文件放在哪里 如何设计有层次高覆盖率的测试
-
测试文件应该放在哪里?
测试文件放在单独文件夹里统一管理
-
如何设计有层次的高覆盖率的测试
我打算设计以下三层测试
- 首先进行每一个服务逻辑的单元测试 保证细颗粒的测试
- 同时对每一个服务进行对应的基准测试(压力测试) 去观察性能指标
- 编写集成测试:将多个模块组合起来,测试整个系统的功能,以确保系统中各个模块之间的交互是正确的
-
加快生成速度的工具: github.com/cweill/gote… gotests
-
下次麻烦一定要写代码同时写测试 重写读逻辑 重新写测试太恼了
第二部分 单元测试:
出现以下问题:
1. 结构体可以进行比较吗? 答:如果包含不可比较的成员则不可以 其他时候可以
不可比较的成员:
在 Go 语言中,Go 结构体有时候并不能直接比较,其基本类型包含:slice、map、function 时,是不能比较的。若强行比较,就会导致出现例子中的直接报错的情况。
2. 结构体怎么打印? 答: %+v
我们使用了一个加速生成test代码的工具 gotests 可以快速生成测试代码测试代码如下
func TestUserGetFeedService(t *testing.T) {
type args struct {
这里面是你函数传入的参数...
}
tests := []struct {
name string
args args
...//这个位置是你希望的返回值
}{
// TODO: Add test cases.
// 也是在这里去生成你要的测试样例
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {//这下方自动根据你要求的返回值个数生成不同的错误代码
got, err := userservice.UserGetFeedService(tt.args.ctx, tt.args.req)
if (err != nil) != tt.wantErr {
t.Errorf("UserGetFeedService() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("UserGetFeedService() = %v, want %v", got, tt.want)
}
})
}
}
第三部分 mock
当我们mock的对象是函数的时候 我们采用 mockey库和 PatchConvey 的方法
样例代码
func TestBad(t *testing.T) {
PatchConvey("TestMockXXX", t, func() {
Mock(good.Good).Return("yes").Build() // mock函数
assert.Equal(t, bad.Bad(), "yes")
})
}
其中 PatchConvey是一个测试框架,它提供了一种方便的方式来模拟其他函数的行为,以便在不改变原来函数的情况下,进行函数的测试。
PatchConvey函数有三个参数,分别是:TestMockXXX、t、func()。TestMockXXX是测试的名称,t是testing.T类型的参数,用于表示测试的上下文;func()是一个回调函数,用于设置模拟函数的行为。
如果把TestMockXXX改成其他名称,不会影响测试结果,但可以更清晰地表明测试的内容。
如果将assert.Equal(t, bad.Bad(), "yes")放到PatchConvey外面,会影响测试结果,因为PatchConvey函数是在每次运行测试用例时都会重新调用,如果把assert.Equal放在外面,那么就不会去模拟good.Good()函数,所以测试结果可能会有出入。
参考材料:
码风略丑 读者见谅 --2023/2/19