Go的單元測試與壓力測試

Go怎么寫測試用例

  • 開發程序其中很重要的一點就是測試,我們如何保證代碼質量,如何保證每個函數都是可運行的,運行結果是正確的,又如何保證寫出來的代碼性能是好的,我們知道單元測試的重點在于發現程序設計或實現的邏輯錯誤,使問題及早暴露,便于問題的定位解決,而性能測試的重點在于發現程序設計的一些問題,讓線上的程序能夠高并發的情況下還能夠保持穩定。
  • Go語言中自帶又一個輕量級的測試框架testing和自帶的go test命令來實現單元測試和性能測試,testing框架及其他語言的中的測試框架類似,你可以給予這個框架寫真對相應函數的測試用例,也可以基于該框架寫相應的壓力測試用例

如何編寫測試用例

  • 由于go test命令只能在一個相應的目錄下執行所有文件,所以我們先創建一個項目目錄gotest,這樣我們所有的代碼和測試代碼都在這個目錄下。我們在該目錄下創建兩個文件:gotest.go和gotest_test.go
  • gotest.go這個文件里面我們是創建了一個包
package gotest

import "errors"

func Division(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除數不能為0")
    }

    return a / b, nil
}
  • gotest_test.go是我們的單元測試文件,單元測試文件必須遵守下面原則:
    • 文件名必須是_test.go結尾,這樣執行go test的時候才會執行到相應的代碼
    • 必須import testing這個包
    • 所有測試函數必須是Test開頭
    • 測試用例會按照源代碼中寫的順序依次執行
    • 測試函數的參數是testing.T,我們可以使用該類型來記錄錯誤或者是測試狀態
    • 測試函數格式:*func TestXxx(t testing.T),Xxx部分可以任意字母數字的組合,但是首字母不能是小寫
    • 函數中通過調用testing.T 的Error,Errorf,FailNow,Fatal,FatalIf方法,說明測試不通過,調用Log方法來記錄測試信息
package gotest

import (
    "testing"
)

func Test_Division_1(t *testing.T) {
    if i, e := Division(6, 2); i != 3 || e != nil { //try a unit test on function
        t.Error("除法函數測試沒通過") // 如果不是如預期的那么就報錯
    } else {
        t.Log("第一個測試通過了") //記錄一些你期望記錄的信息
    }
}

func Test_Division_2(t *testing.T) {
    t.Error("就是不通過")
}

當我們進入到gotest目錄后執行go test會答應以下信息

--- FAIL: Test_Division_2 (0.00s)
        gotest_test.go:16: 就是不通過
FAIL
exit status 1
FAIL    web/gotest      0.006s

由于第二個函數我們直接寫死了t.Error,所以測試不通過。第一個函數沒有打印信息是因為默認情況下go test不會顯示測試通過的信息,我們可以使用帶參數go test -v,這樣就會顯示如下信息:

=== RUN   Test_Division_1
--- PASS: Test_Division_1 (0.00s)
        gotest_test.go:11: 第一個測試通過了
=== RUN   Test_Division_2
--- FAIL: Test_Division_2 (0.00s)
        gotest_test.go:16: 就是不通過
FAIL
exit status 1
FAIL    web/gotest      0.006s

  • 我們將第二個函數做如下修改
func Test_Division_2(t *testing.T) {
    if _, e := Division(6, 0); e == nil { //try a unit test on function
        t.Error("Division did not work as expected.") // 如果不是如預期的那么就報錯
    } else {
        t.Log("one test passed.", e) //記錄一些你期望記錄的信息
    }
}   

再執行go test -v,就會顯示:

=== RUN Test_Division_1
--- PASS: Test_Division_1 (0.00 seconds)
    gotest_test.go:11: 第一個測試通過了
=== RUN Test_Division_2
--- PASS: Test_Division_2 (0.00 seconds)
    gotest_test.go:20: one test passed. 除數不能為0
PASS
ok      gotest  0.013s

如何編寫壓力測試

壓力測試用來檢測函數的性能的,和編寫單元功能的測試的方法類似,壓力測試必須注意以下幾點:

  • 壓力測試用例必須遵循如下格式,其中XXX可以是任意字母數字組合,但是首字母不能是小寫字母
 func BenchmarkXXX(b *testing.B) { ... }
  • go test不會默認執行壓力測試的函數,如果要執行壓力測試需要帶上參數-test.bench,語法:-test.bench="test_name_regex",例如go test.bench="."* 表示測試全部的壓力測試函數
  • 在壓力測試用例中,請記得在循環體內使用testing.B.N,以使測試可以正常運行
  • 文件名也必須是以_test.go結尾

新建壓力測試文件webbench_test.go,代碼如下所示:

func Benchmark_Division(b *testing.B) {
    for i := 0; i < b.N; i++ { //use b.N for looping
        Division(4, 5)
    }
}

func Benchmark_TimeConsumingFunction(b *testing.B) {
    b.StopTimer() //調用該函數停止壓力測試的時間計數
    //做一些初始化的工作,例如讀取文件數據,數據庫連接之類的,
    //這樣這些時間不影響我們測試函數本身的性能
    b.StartTimer() //重新開始時間
    for i := 0; i < b.N; i++ {
        Division(4, 5)
    }
}

執行命令go test -run="webbench_test.go" -test.bench="."*進行webbench_test.go文件的全部壓力測試,可以得到以下結果:

goarch: amd64
pkg: web/gotest
Benchmark_Division-4                    2000000000               0.36 ns/op
Benchmark_TimeConsumingFunction-4       2000000000               0.36 ns/op
PASS
ok      web/gotest      1.500s

上面結果顯示了我們只執行了壓力測試函數,其中函數Benchmark_Division我們執行了2000000000次,每次執行平均時間為0.36ns,函數Benchmark_TimeConsumingFunction我們執行了2000000000次,每次執行平均時間為0.36ns,總共時間花了1.5s

執行命令:go test -run="webbench_test.go" -test.bench="Benchmark_TimeConsumingFunction"用于單獨壓力測試函數Benchmark_TimeConsumingFunction,得到以下結果:

goos: darwin
goarch: amd64
pkg: web/gotest
Benchmark_TimeConsumingFunction-4       2000000000               0.35 ns/op
PASS
ok      web/gotest      0.737s

顯示該函數執行了2000000000次,平均每次執行時間為0.35ns,總共執行時間為0.737s

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容