这是我参与「第五届青训营」伴学笔记创作活动的第 3 天
入门 Go 语言-测试
测试
回归测试,集成测试,单元测试
从左到右,覆盖率逐层变大,成本却逐层降低
单元测试-规则
- 所有测试文件以_test.go结尾
- func TestXxx(*testing.T)
- 初始化逻辑放到TestMain中
单元测试-例子
package main
import "testing"
func HelloTom() string {
return "Jerry"
}
func TestHelloTom(t *testing.T) {
output := HelloTom()
expectOutput := "Tom"
if output != expectOutput {
t.Errorf("Expected %s do not match actual %s", expectOutput, output)
}
}
单元测试-覆盖率
package test
func JudgePassLine(score int16) bool {
if score >= 60 {
return true
}
return false
}
package test
import (
"testing"
)
func TestJudgePassLineTrue(t *testing.T) {
expectOutput := true
output := JudgePassLine(70)
if output != expectOutput {
t.Errorf("Expected %t do not match actual %t", expectOutput, output)
}
}
- 执行语句
go test xxxt.go xxx.go --cover返回结果ok command-line-arguments 0.588s coverage: 66.7% of statements - 我们发现覆盖于只有66.7%是因为只测试了大于60的分支部分没有测试小于60的下面我们添加测试代码
package test
import (
"testing"
)
func TestJudgePassLineTrue(t *testing.T) {
expectOutput := true
output := JudgePassLine(70)
if output != expectOutput {
t.Errorf("Expected %t do not match actual %t", expectOutput, output)
}
}
func TestJudgePassLineFail(t *testing.T) {
expectOutput := false
output := JudgePassLine(50)
if output != expectOutput {
t.Errorf("Expected %t do not match actual %t", expectOutput, output)
}
}
再次执行go test xxxt.go xxx.go --cover我们发现覆盖率已经到达了100%ok command-line-arguments 0.634s coverage: 100.0% of statements
单元测试-Tips
- 一般覆盖率:50%~60%,较高覆盖率80%+
- 测试分支相互独立、全面覆盖
- 测试单元粒度足够小,函数单一职责
单元测试-依赖
外部依赖=>稳定&幂等
单元测试-文件处理
package test
import (
"bufio"
"os"
"strings"
)
func ReadFirstLine() string {
open, err := os.Open("log")
if err != nil {
return ""
}
scanner := bufio.NewScanner(open)
for scanner.Scan() {
return scanner.Text()
}
return ""
}
func ProcseeFirstLine() string {
line := ReadFirstLine()
destLine := strings.ReplaceAll(line, "11", "00")
return destLine
}
单元测试
package test
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestProcseeFirstLine(t *testing.T) {
firstLine := ProcseeFirstLine()
assert.Equal(t, "line00", firstLine)
}
单元测试结果=== RUN TestProcseeFirstLine--- PASS: TestProcseeFirstLine (0.00s)
单元测试-Mock
这里我们对ReadFirstLine打桩测试,不依赖本地文件
func TestProcessFirstLineWithMock(t *testing.T) {
monkey.Patch(ReadFirstLine, func() string {
return "line110"
})
defer monkey.Unpatch(ReadFirstLine)
line := ProcessFirstLine()
assert.Equal(t, "line000", line)
}
基准测试
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力
package test
import "math/rand"
var ServerIndex [10]int
func InitServerIndex() {
for i := 0; i < 10; i++ {
ServerIndex[i] = i + 100
}
}
func Select() int {
return ServerIndex[rand.Intn(10)]
}
对Select进行基准测试
package test
import "testing"
func BenchmarkSelect(b *testing.B) {
InitServerIndex()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Select()
}
}
func BenchmarkSelectParallel(b *testing.B) {
InitServerIndex()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Select()
}
})
}
测试结果
- BenchmarkSelect-12 68482987 18.07 ns/op
- BenchmarkSelectParallel-12 16939533 69.95 ns/op
基准测试-优化
把[rand.Intn(10)]改为更快的[fastrand.Intn(10)]
func FastSelect() int {
return ServerIndex[fastrand.Intn(10)]
}
再次测试
func BenchmarkFastSelectParallel(b *testing.B) {
InitServerIndex()
//重置定时器
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
FastSelect()
}
})
}
- BenchmarkSelectParallel-12 22332769 64.60 ns/op
- BenchmarkFastSelectParallel-12 22082407 51.19 ns/op