go的测试

go测试注意事项

  • go的测试文件需要以_test结尾
  • 测试函数名必须以大写Test开头

表格驱动测试

  • 分离测试数据和测试逻辑
  • 明确的出错信息
  • 可以部分失败
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
func add(a, b int) int {
return a + b
}

func TestAdd(t *testing.T) {
var add =func (a, b int) int {
return a + b
}

var tests = []struct {
a, b, c int
}{
{1, 2, 3},
{1, 5, 6},
{1, 8, 9},
}

for _, tt := range tests {
if actual := add(tt.a, tt.b); actual != tt.c {
t.Errorf("add(%d, %d);"+
"got %d; expected %d", tt.a, tt.b, actual, tt.c)
}
}
}

func TestSubstr(t *testing.T) {
var longestStrInString = func(str string) int {
var length int = 0
var start int = 0
lastOcc := make(map[rune]int)
for i, char := range []rune(str) {
if index, ok := lastOcc[char]; ok && index >= start {
start = i
}
if i-start+1 > length {
length = i - start + 1
}
lastOcc[char] = i
}
return length
}

var tests = []struct {
a string
b int
}{
{"pwbds6786868767867wbertyuio", 11},
{"", 0},
{"这里是你最偶偶的地方", 6},
{"一二三二一", 3},
}

for _, tt := range tests {
if actual := longestStrInString(tt.a); actual != tt.b {
t.Errorf("longestStrInString(%s);"+
"got %d; expected %d", tt.a, actual, tt.b)
}
}
}

go测试命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 测试当前目录所有test文件
go test .

# 生成test的测试结果文件
go test -coverprofile=c.out

# 查看cover的可用命令
go tool cover

# 使用html的方式展示覆盖率
go tool cover -html=c.out

# 查看_test.go的内容
less _test.go

go benchmark和pprof

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// map版本  较短字符串处理速度快
func LongestStrInString(str string) int {
var length int = 0
var start int = 0
lastOcc := make(map[rune]int)
for i, char := range []rune(str) {
if index, ok := lastOcc[char]; ok && index >= start {
start = i
}
if i-start+1 > length {
length = i - start + 1
}
lastOcc[char] = i
}
return length
}


// slice版本的处理 较长字符串处理速度慢
var lastOcc = make([]int, 0xffff)
func LongestStrInStringUpgrade(str string) int {
for i := range lastOcc {
lastOcc[i] = -1
}
var length int = 0
var start int = 0
for i, char := range []rune(str) {
if index := lastOcc[char]; index >= start {
start = i
}
if i-start+1 > length {
length = i - start + 1
}
lastOcc[char] = i
}
return length
}

// benchmark
func BenchmarkLongestStrInString(b *testing.B) {
s := "这里是你最偶偶的地方"
res := 6

b.ResetTimer()
for i := 0; i < b.N; i++ {
actual := LongestStrInString(s)
if actual != res {
b.Errorf("got %d for input %s, expected %d", actual, s, res)
}
}
}
1
2
3
4
5
6
7
8
9
10

# benchmark测试命令
go test -bench .

# 生成性能报告
go test -bench . -cpuprofile cpu.out

# 交互式命令
go tool pprof cpu.out
web #显示运行耗时的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

package main

import (
"errors"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
)

func panicError(writer http.ResponseWriter, request *http.Request) error {
return errors.New("Internal Server Error")
}
func errUserError(writer http.ResponseWriter, request *http.Request) error {
return custom_error{"user error", time.Now(), "position"}
}

func notExistError(writer http.ResponseWriter, request *http.Request) error {
return os.ErrNotExist
}

func forbidError(writer http.ResponseWriter, request *http.Request) error {
return os.ErrPermission
}

func noError(writer http.ResponseWriter, request *http.Request) error {
return nil
}

var tests = []struct {
h appHandler
code int
message string
}{
{panicError, 500, "Internal Server Error"},
{errUserError, 400, "position: user error"},
{notExistError, 404, "Not Found"},
{forbidError, 403, "Forbidden"},
{noError, 200, ""},
}

// 使用假的http请求来测试
func TestErrWrapper(t *testing.T) {
for _, tt := range tests {
f := errWraper(tt.h)
response := httptest.NewRecorder()
request := httptest.NewRequest(
http.MethodGet,
"http://www.baidu.com",
nil,
)
f(response, request)
verifyResponse(response.Result(), tt.code, tt.message, t)
}
}

// 使用真实的http请求来测试
func TestErrWraperInServer(t *testing.T) {
for _, tt := range tests {
f := errWraper(tt.h)
server := httptest.NewServer(http.HandlerFunc(f))
resp, _ := http.Get(server.URL)
verifyResponse(resp, tt.code, tt.message, t)
}
}

func verifyResponse(resp *http.Response, expectedCode int, expectedMsg string, t *testing.T) {
b, _ := ioutil.ReadAll(resp.Body)
body := strings.Trim(string(b), "\n")
if resp.StatusCode != expectedCode || body != expectedMsg {
t.Errorf("expect (%d, %s);"+
"got (%d, %s)",
expectedCode, expectedMsg,
resp.StatusCode, body)
}
}