Golang 学习笔记11-单元测试

单元测试

意义

  1. 确保每个函数是可运行,并且运行结果是正确的
  2. 确保写出来的代码性能是好的
  3. 单元测试能及时的发现程序设计或实现的逻辑错误,使问题暴露,便于问题的定位解决,而性能测试的重点在于发现程序设计上的一些问题,让程序能够在高并发的情况下还能保持稳定

Go 语言推荐测试文件和源代码文件放在一块,测试文件以 _test.go 结尾

需要注意的是

  1. 测试用例文件名必须以_test.go结尾
  2. 测试用例函数必须以Test开头,一般来说就是Test+被测试的函数名
  3. 文件夹不能用中文,否则使用终端 cd 到文件夹下,使用以下命令
go test calc_test.go calc.go -v
=== RUN   TestAdd
    calc_test.go:8: 测试失败
--- FAIL: TestAdd (0.00s)
FAIL
FAIL    command-line-arguments  1.078s
FAIL

例子

源文件

package main

func Add(n1, n2 int) int {
	return n1 + n2 + 1
}

测试文件

package main

import "testing"

func TestAdd(t *testing.T) {
	res := Add(1, -1)
	if res != 0 {
		t.Errorf("测试失败")
		return
	}
	t.Logf("测试通过")
}

-v 参数会显示每个用例的测试结果

-run参数可以指定测试某个函数

单元测试框架提供的日志方法

方 法 备 注 测试结果
Log 打印日志,同时结束测试 PASS
Logf 格式化打印日志,同时结束测试 PASS
Error 打印错误日志,同时结束测试 FAIL
Errorf 格式化打印错误日志,同时结束测试 FAIL
Fatal 打印致命日志,同时结束测试 FAIL
Fatalf 格式化打印致命日志,同时结束测试 FAIL

如果不同的测试用例每次都这么写很麻烦

子测试

如果需要给一个函数,调用不同的测试用例,可以使用子测试

子测试里面的Fatal,是不会终止程序的

package main

import "testing"

func TestAdd(t *testing.T) {
	t.Run("add1", func(t *testing.T) {
		if Add(1, -1) != 1 {
			t.Errorf("测试失败")
			return
		}

	})
	t.Run("add1", func(t *testing.T) {
		if Add(1, -1) != 2 {
			t.Errorf("测试失败")
			return
		}
	})

	//res := Add(1, -1)
	//if res != 0 {
	//	t.Errorf("测试失败")
	//	return
	//}
	//t.Logf("测试通过")
}

如果测试用例很多,还可以用一个类似表格去表示

package main

import (
	"testing"
)

func TestAdd(t *testing.T) {
	cases := []struct {
		Name           string
		A, B, Expected int
	}{
		{"a1", 2, 3, 5},
		{"a2", 2, -3, -1},
		{"a3", 2, 0, 2},
	}
	for _, s := range cases {
		t.Run(s.Name, func(t *testing.T) {
			if Add(s.A, s.B) != s.Expected {
				t.Errorf("测试失败")
				return
			}

		})
	}
}

如果用例较多,还可以通过读取 csv 的文件进行测试

TestMain函数

它是测试的入口

我们可以在TestMain里面实现测试流程的生命周期

package main

import (
  "fmt"
  "os"
  "testing"
)

// 测试前执行
func setup() {
  fmt.Println("Before all tests")
}

// 测试后执行
func teardown() {
  fmt.Println("After all tests"
}

func Test1(t *testing.T) {
  fmt.Println("I'm test1")
}

func Test2(t *testing.T) {
  fmt.Println("I'm test2")
}

// 必须叫这个名字  测试主入口
func TestMain(m *testing.M) {
  // 测试前执行
  setup()
  code := m.Run()
  // 测试后执行
  teardown()
  os.Exit(code)
}