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

posted @ 2020-12-24 17:58  柔南青空  阅读(81)  评论(0编辑  收藏  举报