go test 上篇


前言

Go語言本身集成了輕量級的測試框架,由go test命令和testing包組成。包含單元測試和壓力測試,是保證我們編寫健壯Golang程序的有效工具。

 

演示環境

$ uname -a
Darwin 18.6.0 Darwin Kernel Version 18.6.0: Thu Apr 25 23:16:27 PDT 2019; root:xnu-4903.261.4~2/RELEASE_X86_64 x86_64
$ go version
go version go1.12.4 darwin/amd64

 

示例

老規矩,我會用一個簡單的示例演示go test的用法,讓大家有一個直觀的感受。

$ ls
my.go my_test.go
$ go test -v
=== RUN   TestAbs
--- PASS: TestAbs (0.00s)
PASS
ok      mytest    0.006s

my.go文件內容:

package mytest

func Abs(a int) int {
    if a < 0 {
        return -1*a
    }
    return a
}

my_test.go文件的內容:

package mytest

import "testing"

func TestAbs(t *testing.T) {
    result := Abs(-1)
    if result != 1 {
        t.Errorf("Abs(-1) = %d; want 1", result)
    }
}

可以看出,測試文件是以_test.go結尾的文件,包含函數名TestXXX的文件簽名func (t *testing.T)。測試框架會按函數定義的順序依次執行Test開頭的函數。如果測試函數調用錯誤函數,比如t.Error,t.Fail,那么測試就會認為是失敗的。但是不會強制退出,測試程序還是會接着往下運行,除非調用t.Fatal,就會打印錯誤信息,並且強制退出。go test會自動編譯運行_test.go結尾的文件,go build不會編譯_test.go結尾的文件,所以不用擔心test文件和正式文件定義為同一個包導致包大小增大。

 

詳細用法

go test執行時會編譯_test結尾的文件,執行文件中以Test,Benchmark,Example 開頭的測試函數。建議_test.go文件和源文件聲明為同一個包。單元測試函數TestXXX的參數是testing.T,BenchmarkXXX的參數是testing.B,函數內以b.N作為循環次數,其中N會動態變化。可以通過testing.T的Error,Errorf,Fail,Fatal,Fatalf 來說明測試不通過。

 

表格驅動測試

上述的示例單元測試用了-1這個測試用例來演示測試用法,但是在實際生產中我們編寫一個測試函數肯定會有多種測試用例,各種邊界條件,那這種情況應該怎么辦呢?難道要每個測試用例拷貝一份上述的測試函數嗎,顯然是不合適的。這就介紹接下來的表格驅動測試(table driven test):

package mytest

import "testing"

func TestAbs(t *testing.T) {
    var testcases = []struct {
        in int
        out int
    }{
        {-1, 1},
        {0, 0},
        {2, 2},
        {123, 123},
        {-30, -30},
    }
    for _, tc := range testcases {
        result := Abs(tc.in)
        if result != tc.out {
            t.Fatalf("Abs(%d) = %d; want %d", tc.in, result, tc.out)
        }
    }

}

表格的每一項是一個完整的測試用例,包含輸入信息和期望的輸出結果,有時候還包含測試用例名稱等額外信息。這樣我們就可以在表格里面編寫各種測試用例場景,包括常規場景,邊界場景,和一些異常場景。運行結果為:

$ go test -v
=== RUN   TestAbs
--- FAIL: TestAbs (0.00s)
    my_test.go:19: Abs(-30) = 30; want -30
FAIL
exit status 1
FAIL    mytest    0.005s

 

性能測試

性能測試函數以是Benchmark開頭,格式為:

func Benchmark(b *testing.B)

go test 默認是不會運行_test.go文件中的Benchmark函數,需要通過-bench選項開啟。演示代碼:

package mytest

import "testing"

func BenchmarkAbs(b *testing.B) {
    for i := 0; i < b.N; i++ {
        result := Abs(i)
        if result != i {
            b.Errorf("benchmark faild, abs(%d) result %d, except %d", i, result, i)
        }
    }
}

運行結果:

$ go test -bench=".*"
goos: darwin
goarch: amd64
pkg: mytest
BenchmarkAbs-12        2000000000             0.26 ns/op
PASS
ok      mytest    0.553s

-bench后面跟的是正則表達式,我們可以指定需要匹配運行的benchmark函數,示例中的.*表示運行所有的benchmark函數。

上述結果顯示總共運行了0.553s,一共運行了2000000000次,平均每次運行的時間是0.26納秒。

 

總結

文章介紹了Go語言自帶的go test測試框架的單元測試和性能測試方法。下篇將會講解gomock模擬實際的生產接口。

 

參考

https://golang.org/pkg/testing/

https://github.com/golang/go/wiki/TableDrivenTests

https://golang.org/doc/code.html#Testing

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM