GO编程(打卡)-Task12: 单元测试
单元测试
go test 工具
包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中
单元测试函数 函数名前缀为Test 测试程序的一些逻辑行为是否正确
基准测试函数 函数名前缀为Benchmark 测试函数的性能
示例函数 函数名前缀为Example 为文档提供示例文档
测试框架
testing
测试命令go test xxx
测试文件xxx_test.go
测试函数
-
格式
每个测试函数必须导入
testing
包, 参数t
用于报告测试失败和附加的日志信息func TestName(t *testing.T){ //... }
-
示例
// split/split.go package split import "strings" func Split(s, sep string) (result []string) { i := strings.Index(s, sep) for i > -1 { result = append(result, s[:i]) s = s[i+1:] // s = s[i+len(sep):] // 这里使用len(sep)获取sep的长度 i = strings.Index(s, sep) } result = append(result, s) return }
// split/split_test.go package split import ( "reflect" "testing" ) func TestSplit(t *testing.T) { // 测试函数名必须以Test开头,必须接收一个*testing.T类型参数 got := Split("a:b:c", ":") // 程序输出的结果 want := []string{"a", "b", "c"} // 期望的结果 if !reflect.DeepEqual(want, got) { // 因为slice不能比较直接,借助反射包中的方法比较 t.Errorf("excepted:%v, got:%v", want, got) // 测试失败输出错误提示 } }
在split路径下运行
go test
添加测试用例
func TestMoreSplit(t *testing.T) { got := Split("abcd", "bc") want := []string{"a", "d"} if !reflect.DeepEqual(want, got) { t.Errorf("excepted:%v, got:%v", want, got) } }
运行指定测试用例
修改split函数中的代码
s = s[i+1:]
为s = s[i+len(sep):]
-
测试组 添加更多测试用例
func TestSplit(t *testing.T) { // 定义一个测试用例类型 type test struct { input string sep string want []string } // 定义一个存储测试用例的切片 tests := []test{ {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}}, {input: "a:b:c", sep: ",", want: []string{"a:b:c"}}, {input: "abcd", sep: "bc", want: []string{"a", "d"}}, {input: "沙河有沙又有河", sep: "沙", want: []string{"河有", "又有河"}}, } // 遍历切片,逐一执行测试用例 for _, tc := range tests { got := Split(tc.input, tc.sep) if !reflect.DeepEqual(got, tc.want) { t.Errorf("excepted:%#v, got:%#v", tc.want, got) } } }
-
子测试 便于定位测试用例是否通过
func TestSplit(t *testing.T) { type test struct { // 定义test结构体 input string sep string want []string } tests := map[string]test{ // 测试用例使用map存储 "simple": {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}}, "wrong sep": {input: "a:b:c", sep: ",", want: []string{"a:b:c"}}, "more sep": {input: "abcd", sep: "bc", want: []string{"a", "d"}}, "leading sep": {input: "沙河有沙又有河", sep: "沙", want: []string{"河有", "又有河"}}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // 使用t.Run()执行子测试 got := Split(tc.input, tc.sep) if !reflect.DeepEqual(got, tc.want) { t.Errorf("excepted:%#v, got:%#v", tc.want, got) } }) } }
运行指定子测试用例
-
测试覆盖率
测试覆盖率是你的代码被测试套件覆盖的百分比
go test -cover
查看覆盖率
基准函数
-
格式
基准测试必须要执行
b.N
次func BenchmarkName(b *testing.B){ // ... }
-
示例
func BenchmarkSplit(b *testing.B) { for i := 0; i < b.N; i++ { Split("沙河有沙又有河", "沙") } }
go test -bench=Split
-benchmem
参数,来获得内存分配的统计数据
示例函数
-
格式
基准测试必须要执行
b.N
次func ExampleName(b *testing.B){ // ... }
-
示例
func ExampleSplit() { fmt.Println(Split("a:b:c", ":")) fmt.Println(Split("沙河有沙又有河", "沙")) // Output: // [a b c] // [ 河有 又有河] }
参考
https://github.com/datawhalechina/go-talent/blob/master/10.反射机制.md
https://www.cnblogs.com/nickchen121/p/11517443.html