Go之测试

0 阅读3分钟

1.单元测试:

先创建一个包goTest.然后里面创建两个文件.结构如下.

unit.go为源代码文件.unit_test.go为测试文件.要保证测试文件以_test.go结尾.

1.1源码函数Add():

package goTest

func Add(a int, b int) int {
    return a + b
}

1.2测试函数TestAdd():

package goTest

import "testing"

func TestAdd(t *testing.T) {
    var a = 1
    var b = 2
    var expected = 3
    add := Add(a, b)
    if add != expected {
       t.Errorf("add(%d,%d) != %d\n", a, b, expected)
    }
}

执行结果:

测试函数命名规则为Testxxx.其中Test为单元测试固定开头.go test会执

行以此为开头的函数.紧跟Test是以首字母大写的单词.用于识别待测试函

数.

2.基准测试:

创建两个文件.benchmark.go为源码文件和benchmark_test.go为测试

文件.

2.1源码函数:

package goTest

// 不预分配内存.
func MakeSliceWithoutAlloc() []int {
    var newSlice []int

    for i := 0; i < 100000; i++ {
       newSlice = append(newSlice, i)
    }
    return newSlice
}

// 通过切片预分配内存.
func MakeSliceWithPreAlloc() []int {
    var newSlice []int

    newSlice = make([]int, 0, 100000)

    for i := 0; i < 100000; i++ {
       newSlice = append(newSlice, i)
    }
    return newSlice
}

两个方法都会构建一个100000的切片.一个会预分配内存.一个不会预分配内存.

2.2测试函数:

package goTest

import "testing"

func BenchmarkMakeSliceWithPreAlloc(b *testing.B) {
    for i := 0; i < b.N; i++ {
       MakeSliceWithPreAlloc()
    }
}

func BenchmarkMakeSliceWithoutAlloc(b *testing.B) {
    for i := 0; i < b.N; i++ {
       MakeSliceWithoutAlloc()
    }
}

函数命名规则为Benchmarkxxx.xxx为自定义标识.需要大写字母开头.通常为待测

函数.

2.3测试结果:

3.示例测试:

创建两个文件.example.go为源码文件和example_test.go为测试文件.

3.1源码函数:

package goTest

import "fmt"

func SayHello() {
	fmt.Println("Hello World")
}

func SayGoodBye() {
	fmt.Println("Hello World")
	fmt.Println("go")
}

func PrintNames() {
	students := make(map[int]string, 4)
	students[1] = "1"
	students[2] = "2"
	students[3] = "3"
	students[4] = "4"
	for i := range students {
		fmt.Println(students[i])
	}
}

3.2测试函数:

package goTest

func ExampleSayHello() {
    SayHello()
    //Output: Hello World
}

func ExampleSayGoodBye() {
    SayGoodBye()
    //Output:
    //Hello World
    //go
}

func ExamplePrintNames() {
    PrintNames()
    //Unordered output:
    //1
    //2
    //3
    //4
}

待测函数只有一行输出.使用//Output:检测.

待测函数有多行输出.使用//Output检测.其中期望值也是多行.

待测函数有多行输出.但输出次序不确定.使用//Unordered output检测.

注:比较字符串时会忽略前后的空白字符.

3.3执行结果:

4.模糊测试:

创建两个文件.fuzz.go为源码文件和fuzz_test.go为测试文件.

4.1模糊源码函数:

package goTest

import (
    "errors"
    "unicode/utf8"
)

func Reverse(s string) (string, error) {
    if !utf8.ValidString(s) {
       return s, errors.New("invalid utf8 string")
    }

    b := []byte(s)
    for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 {
       b[i], b[j] = b[j], b[i]
    }
    return string(b), nil
}

4.2模糊测试函数:

package goTest

import (
    "testing"
    "unicode/utf8"
)

func FuzzReverse(f *testing.F) {
    testcases := []string{"hello world", "     ", "!12345"}
    for _, tc := range testcases {
       //输入测试种子.
       f.Add(tc)
    }

    f.Fuzz(func(t *testing.T, s string) {
       //忽略够早的无效字符.(非utf-8编码字符串.)
       if !utf8.ValidString(s) {
          return
       }
       rev, err := Reverse(s)
       if err != nil {
          t.Fatalf("unexpected error:%v", err)
       }

       if !utf8.ValidString(rev) {
          t.Fatalf("Reverse produced invalid utf-8 string %q", rev)
       }

       twoRev, err := Reverse(rev)
       if err != nil {
          t.Fatalf("unexpected error:%v", err)
       }
       if s != twoRev {
          t.Errorf("before:%q, after:%q", s, twoRev)
       }
    })
}

4.2执行结果:

image.png

蝉它不惊不扰.



考虑到过于碎片化.把一些文章维护到了语雀.www.yuque.com/itbosunmian… 《Go.》 密码:xbkk.欢迎大家提意见.