Go語(yǔ)言單元測(cè)試

1. 概述

單元測(cè)試(unit testing) 是指對(duì)軟件 中的 最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證

Go語(yǔ)言自身提供了一套輕量級(jí)的單元測(cè)試和性能測(cè)試系統(tǒng),符合規(guī)則的測(cè)試代碼會(huì)在運(yùn)行測(cè)試時(shí)被自動(dòng)識(shí)別執(zhí)行

2. 基礎(chǔ)測(cè)試

看看一個(gè)基本的測(cè)試案例是怎么寫(xiě)的

文件結(jié)構(gòu)如下

|
|_main.go
|_utils
|___func1.go
|___func1_test.go
|___sham_test.go

func1.go

package utils

func AddTwoNums(x, y int) (sum int) {
    sum = x + y
    return
}

func AddUp(x int) int {
    if x < 2 {
        return x
    }
    sum := 0
    for i := 0; i <= x; i++ {
        sum += i
    }
    return sum
}

main.go

package main

import (
    "utils"
    "fmt"
)

func main(){
     // 調(diào)用函數(shù)AddtwoNums
    sum := utils.AddTwoNums(9,8)
    fmt.Println(sum) // 17
    // 調(diào)用函數(shù)AddUp
    sum1 := utils.AddUp(100)
    fmt.Println(sum1) // 5050
}

接下來(lái)我們看看測(cè)試用例怎么寫(xiě)

func1_test.go

package utils

import (
    "testing" // 導(dǎo)入testing包
)

// AddTwoNums的測(cè)試用例1
// 測(cè)試AddTwoNums函數(shù) 結(jié)果正確
func TestAddTwoNums1(t *testing.T) {
    sum := AddTwoNums(9,8)
    if sum != 17{
        t.Error("AddTwoNums is failed",sum)
    }
}
// AddTwoNums的測(cè)試用例2
// 測(cè)試AddTwoNums函數(shù) 結(jié)果錯(cuò)誤
func TestAddTwoNums2(t *testing.T) {
    sum := AddTwoNums(100,100)
    if sum != 2000{
        t.Error("AddTwoNums is failed",sum)
    }
}
// AddUp的測(cè)試用例
// 測(cè)試AddUp函數(shù)
func TestAddUp(t *testing.T) {
    sum := AddUp(100)
    if sum != 5050{
        t.Error("AddUp is failed",sum)
    }
}

sham_test.go

package utils

import "testing"

func TestFunc1(t *testing.T) {
    t.Log("TestFunc1 run")
}
func TestFunc2(t *testing.T) {
    info := "TestFunc12 run"
    t.Log(info + "===test log the method name `Log`")
    t.Logf("output : %s", info+"===test log the method name `Logf`")
    t.Error(info + "===test log the method name `Error`")
    t.Errorf("output : %s", info+"===test log the method name `Errorf`")
    t.Fatal(info + "===test log the method name `Fatal`")
    t.Fatalf("output : %s", info+"===test log the method name `Fatalf`")
}

我們啟動(dòng)單元測(cè)試

使用的命令是 go test

PS:要查看這個(gè)命令這么使用 ,可以查看幫助文檔 在命令行中執(zhí)行 go help testflag

執(zhí)行該目錄下的所有測(cè)試用例

-v 顯示詳細(xì)的流程

go test -v

=== RUN   TestAddTwoNums1
--- PASS: TestAddTwoNums1 (0.00s)
=== RUN   TestAddTwoNums2
--- FAIL: TestAddTwoNums2 (0.00s)
    func1_test.go:20: AddTwoNums is failed 200
=== RUN   TestAddUp
--- PASS: TestAddUp (0.00s)
=== RUN   TestFunc1
--- PASS: TestFunc1 (0.00s)
    sham_test.go:6: TestFunc1 run
=== RUN   TestFunc2
--- PASS: TestFunc2 (0.00s)
    sham_test.go:9: TestFunc12 run
FAIL
exit status 1
FAIL    GoNote/chapter10/demo3/utils    0.386s

執(zhí)行指定的單元測(cè)試用例

-run 運(yùn)行需要單獨(dú)執(zhí)行的測(cè)試用例

go test -v -run TestAddUp

=== RUN   TestAddUp
--- PASS: TestAddUp (0.00s)
PASS
ok      GoNote/chapter10/demo3/utils    0.392s

執(zhí)行測(cè)試文件中的所有測(cè)試用例

go test -v sham.go

=== RUN   TestFunc1
--- PASS: TestFunc1 (0.00s)
    sham_test.go:6: TestFunc1 run
=== RUN   TestFunc2
--- FAIL: TestFunc2 (0.00s)
    sham_test.go:10: TestFunc12 run===test log the method name `Log`
    sham_test.go:11: output : TestFunc12 run===test log the method name `Logf`
    sham_test.go:12: TestFunc12 run===test log the method name `Error`
    sham_test.go:13: output : TestFunc12 run===test log the method name `Errorf`
    sham_test.go:14: TestFunc12 run===test log the method name `Fatal`
FAIL
FAIL    command-line-arguments  0.383s

通過(guò)上面的例子,總結(jié)如下

  • 測(cè)試用例文件名必須以 _test 結(jié)尾
  • 測(cè)試用例函數(shù)名必須以 Test開(kāi)頭
  • 測(cè)試用例函數(shù)的形參必須是 *testing.T 類型
  • 單個(gè)測(cè)試文件中可以有多個(gè)測(cè)試用例
  • 可以使用多個(gè)測(cè)試用例測(cè)試同一個(gè)內(nèi)容
  • 測(cè)試用例函數(shù)不需要放在 main 函數(shù)也能執(zhí)行
  • PASS 表示測(cè)試用例運(yùn)行成功 , FAIL 表示測(cè)試用例運(yùn)行失敗

單元測(cè)試框架提供的日志方法

方法名 含義
Log 打印日志
Logf 格式化打印日志
Error 打印錯(cuò)誤日志, 將測(cè)試函數(shù)標(biāo)記為失敗,但是繼續(xù)運(yùn)行
Errorf 格式化打印錯(cuò)誤日志 ,將測(cè)試函數(shù)標(biāo)記為失敗,但是繼續(xù)運(yùn)行
Fatal 打印致命錯(cuò)誤日志,將測(cè)試函數(shù)標(biāo)記為失敗并停止執(zhí)行
Fatalf 格式化打印致命錯(cuò)誤日志,將測(cè)試函數(shù)標(biāo)記為失敗并停止執(zhí)行

2.1 提示 build failed ?

PS : 在執(zhí)行測(cè)試文件的時(shí)候可能會(huì)出現(xiàn)類似下面的情況

$ go test func1_test.go
# command-line-arguments [command-line-arguments.test]
.\func1_test.go:10:9: undefined: AddTwoNums
.\func1_test.go:19:9: undefined: AddTwoNums
.\func1_test.go:28:9: undefined: AddUp
FAIL    command-line-arguments [build failed]

我們測(cè)試的兩個(gè)函數(shù) AddTwoNumsAddUp 提示未定義, 最后提示 命令行參數(shù)處理 構(gòu)建失敗

如何解決呢?

執(zhí)行測(cè)試命令帶上原文件即可

$ go test -v func1_test.go func1.go
=== RUN   TestAddTwoNums1
--- PASS: TestAddTwoNums1 (0.00s)
=== RUN   TestAddTwoNums2
--- FAIL: TestAddTwoNums2 (0.00s)
   func1_test.go:21: AddTwoNums is failed 200
=== RUN   TestAddUp
--- PASS: TestAddUp (0.00s)
FAIL
FAIL    command-line-arguments  0.336s

3. 基準(zhǔn)測(cè)試

基準(zhǔn)測(cè)可以測(cè)試一段程序的運(yùn)行性能及耗費(fèi)CPU的程度

寫(xiě)法上和測(cè)試用例的類似

package utils

import (
    "fmt"
    "testing"
)

// 基準(zhǔn)測(cè)試 demo
func BenchmarkDemo1(b *testing.B) {
    var n int
    // b.N 是測(cè)試框架提供
    for i := 0; i < b.N; i++ {
        n++
    }

}
func BenchmarkDemo2(b *testing.B) {

}

// 基準(zhǔn)測(cè)試 測(cè)試函數(shù)AddTwoNums
func BenchmarkAddTwoNums(b *testing.B) {
    for i := 0; i < b.N; i++ {
        sum := AddTwoNums(i, i)
        fmt.Sprintf("%d",sum)
    }
}

執(zhí)行測(cè)試文件

$ go test -v -bench=. -benchmem -benchtime=10s bm_test.go func1.go
goos: windows
goarch: amd64
BenchmarkDemo1-4                10000000000              0.28 ns/op            0 B/op          0 allocs/op
BenchmarkDemo2-4                10000000000              0.00 ns/op            0 B/op          0 allocs/op
BenchmarkAddTwoNums-4           100000000              112 ns/op              20 B/op          2 allocs/op
PASS
ok      command-line-arguments  14.575s

命令說(shuō)明

-bench=. 參數(shù)表示運(yùn)行 bm_test.go 文件中所有的基準(zhǔn)測(cè)試 ,如果想單獨(dú)運(yùn)行某個(gè)基準(zhǔn)測(cè)試帶上對(duì)應(yīng)的名稱即可,例如 -bench=BenchmarkAddTwoNums

-benchmem 參數(shù)表示顯示內(nèi)存分配情況

-benchtime= 參數(shù)表示自定義測(cè)試時(shí)間

測(cè)試結(jié)果說(shuō)明

-4 表示4個(gè)CPU線程執(zhí)行

ns/op 表示每一個(gè)操作消耗多少時(shí)間,單位是 納秒ns

B/op 表示每一次操作需要分配的字節(jié)數(shù)

allocs/op 表示每次執(zhí)行分配了多少次

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末伺帘,一起剝皮案震驚了整個(gè)濱河市兄纺,隨后出現(xiàn)的幾起案子搬葬,更是在濱河造成了極大的恐慌禁谦,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扁誓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蚀之,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門蝗敢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人足删,你說(shuō)我怎么就攤上這事寿谴。” “怎么了失受?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵讶泰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拂到,道長(zhǎng)痪署,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任兄旬,我火速辦了婚禮狼犯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘领铐。我一直安慰自己悯森,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布罐孝。 她就那樣靜靜地躺著,像睡著了一般肥缔。 火紅的嫁衣襯著肌膚如雪莲兢。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天续膳,我揣著相機(jī)與錄音改艇,去河邊找鬼。 笑死坟岔,一個(gè)胖子當(dāng)著我的面吹牛谒兄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播社付,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼承疲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼邻耕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起燕鸽,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兄世,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后啊研,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體御滩,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年党远,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了削解。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沟娱,死狀恐怖氛驮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情花沉,我是刑警寧澤柳爽,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站碱屁,受9級(jí)特大地震影響磷脯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娩脾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一赵誓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柿赊,春花似錦俩功、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至胰挑,卻和暖如春蔓罚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞻颂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工豺谈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贡这。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓茬末,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盖矫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丽惭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容