單元測試
- 單元測試(Unit Tests, UT) 是一個優(yōu)秀項目不可或缺的一部分,特別是在一些頻繁變動和多人合作開發(fā)的項目中尤為重要。你或多或少都會有因?yàn)樽约旱奶峤唬瑢?dǎo)致應(yīng)用掛掉或服務(wù)宕機(jī)的經(jīng)歷。比如我就曾經(jīng)就因?yàn)榇蛴×藄ql,而忘記關(guān)閉,導(dǎo)致所有的接口異常(允悲)。還有就是如果你優(yōu)化了一些代碼邏輯,優(yōu)化了某個函數(shù)。那么我們怎么保證我們的正確性呢?那么幾個測試用例或許就可以解決這個問題。
測試文件的命名
- go語言是支持單元測試的,測試文件是_test.go結(jié)尾的文件名
測試用例的命名
- 測試用例名稱一般命名為 Test 加上待測試的方法名。比如TestAdd(),測試用的參數(shù)有且只有一個,在這里是
t *testing.T
簡單入門
- 我們來寫一個Add函數(shù),創(chuàng)建文件add.go
package main
import "fmt"
func main() {
sum := Add(1, 2)
fmt.Println(sum)
}
func Add(a int, b int) int {
return a + b
}
- 我們在add.go目錄下創(chuàng)建一個add_test.go的測試文件
package main
import (
"testing"
)
func TestAdd(t *testing.T) {
testData := []struct {
a int
b int
c int
}{
{1, 2, 3},
{4, 5, 9},
{50, 5, 5},
}
ans := 0
for _, data := range testData {
if ans = Add(data.a, data.b); ans != data.c {
t.Errorf("%d + %d expected %d,but %d got", data.a, data.b, data.c, ans)
}
}
}
我們先來認(rèn)識一下ide調(diào)試工具,當(dāng)然這些調(diào)試我們在命令也是可以運(yùn)行的
- Run 執(zhí)行腳本
- Debug 開啟Debug模式
- coverprofile 代碼覆蓋率
- CPU Profiler cup分析
- Memory Profiler 內(nèi)存分析 對象、堆的分析和內(nèi)存泄漏等
- Blocking Profiler 記錄 goroutine的阻塞情況,等待和同步情況,timer/channel通訊等各項細(xì)節(jié)
-
Mutex Profiler 互斥鎖分析,包括各種競爭情況
在這里插入圖片描述
-
我通過ide運(yùn)行一下
在這里插入圖片描述 -
我們也可以使用ide的debug功能打斷點(diǎn)調(diào)試
在這里插入圖片描述 -
命令行測試,首先我們進(jìn)入add.go目錄
在這里插入圖片描述
代碼覆蓋率
-
IDE調(diào)試
在這里插入圖片描述 - 我們使用命令行再試一下
zhangguofu@zhangguofudeMacBook-Pro add (master) $ go test -coverprofile=c.out
--- FAIL: TestAdd (0.00s)
add_test.go:20: 50 + 5 expected 5,but 55 got
FAIL
coverage: 33.3% of statements
exit status 1
FAIL goapp/src/learngo/add 0.502s
zhangguofu@zhangguofudeMacBook-Pro add (master) $ ls
add.go add_test.go c.out
zhangguofu@zhangguofudeMacBook-Pro add (master) $ cat c.out
mode: set
goapp/src/learngo/add/add.go:5.13,8.2 2 0
goapp/src/learngo/add/add.go:10.28,12.2 1 1
我們發(fā)現(xiàn)多了一個c.out 文件,但是里面的內(nèi)容我們看不太懂,我們借助工具go tool cover ,查看代碼覆蓋的相關(guān)命令幫助
在這里插入圖片描述
我們使用` go tool cover -html=c.out``,此時會打開一個html頁面,上面標(biāo)注了我們代碼覆蓋的情況
在這里插入圖片描述
性能測試
- 我們通過一個獲取最長不重復(fù)字符串函數(shù)來測試一下性能
- 函數(shù)代碼 在add.go文件中
/**
最大字符串不重復(fù)
*/
func Repeat(s string) int {
//保持最大不重復(fù)串
lastOccur := make(map[string]int)
start := 0
max := 0
for k, v := range []rune(s) {
if index, ok := lastOccur[string(v)]; ok && start <= index {
start = index + 1
}
if max < k-start+1 {
max = k - start + 1
}
lastOccur[string(v)] = k
}
return max
}
- 性能測試代碼 在add_test.go文件中
func BenchmarkRepeat(b *testing.B) {
str := "不經(jīng)歷風(fēng)雨,怎么見彩虹?沒有人能隨隨便便成功"
data := struct {
content string
res int
}{
str,
17,
}
for i := 0; i < b.N; i++ {
if len := Repeat(data.content); len != 17 {
b.Error("the program is wrong")
}
}
}
在這里插入圖片描述
- 結(jié)果是3ms左右,我們加長一點(diǎn)看看
func BenchmarkRepeat(b *testing.B) {
str := "不經(jīng)歷風(fēng)雨,怎么見彩虹?沒有人能隨隨便便"
for i := 0; i < 20; i++ {
str += str
}
b.Logf("the len of str is %d", len(str))
b.ResetTimer() //忽略上面的計算時間
for i := 0; i < b.N; i++ {
Repeat(str)
}
}
-
我們發(fā)現(xiàn)對于計算6m文件中的不重復(fù)字符串,程序執(zhí)行了大概是16s左右,這個感覺很慢了,對不對,但是我們想看程序是時間花在哪里了
在這里插入圖片描述 - 和代碼覆蓋率的命令類似。我執(zhí)行命令
zhangguofu@zhangguofudeMacBook-Pro add (master) $ go test -bench . -cpuprofile cpu.out
goos: darwin
goarch: amd64
pkg: goapp/src/learngo/add
BenchmarkRepeat-8 1 1541179761 ns/op
--- BENCH: BenchmarkRepeat-8
add_test.go:33: the len of str is 62914560
PASS
ok goapp/src/learngo/add 2.077s
zhangguofu@zhangguofudeMacBook-Pro add (master) $ ls
add.go add.test add_test.go c.out cpu.out
zhangguofu@zhangguofudeMacBook-Pro add (master) $ less cpu.out
"cpu.out" may be a binary file. See it anyway?
發(fā)現(xiàn)生成的cpu.out 是一個二進(jìn)制文件,我們使用go tool pprof cpu.out 查看,進(jìn)入交互模式
在這里插入圖片描述
我輸入web格式的,報錯說需要安裝Graphviz ,那就安裝吧 下載地址 如果安裝失敗 可以參考我這篇文章解決brew 安裝軟件失敗的問題
- 再次輸入
go tool pprof cpu.out輸入web
沒有報錯了,但是此處我碰到一個個問題。就是我的虛擬機(jī)(mac上面裝的win10)會默認(rèn)打開svg 文件,很煩人
解決方式
在這里插入圖片描述
并且設(shè)置谷歌瀏覽器為默認(rèn)打開方式
在這里插入圖片描述
- 最終,我們打開了這個文件,這里面箭頭越粗,代表花費(fèi)的時間越長,我們可以根據(jù)結(jié)果 對我們的程序進(jìn)行優(yōu)化,比如在這里,我們看到是string encode decode 很浪費(fèi)時間,那么我們是不是可以選擇更合適的數(shù)據(jù)類型來存儲我們的數(shù)據(jù)呢,比如我們存的是
abc我愛中國,那么再計算中,來回轉(zhuǎn)換是很麻煩的,我們是不是可以轉(zhuǎn)換為int32來計算呢。
在這里插入圖片描述 - golang的單元測試和性能測試就先到這里了。喜歡可以點(diǎn)贊哦?。?/li>
