Golang 測(cè)試教程

GoCommunity.png

How to write test with golang

代碼示例

  • TDD(Test-Driven development) 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)
  • 內(nèi)置的 testing 庫(kù) 佃蚜、 表格驅(qū)動(dòng)髓需、樣本測(cè)試置吓、TestMain
  • 第三方:goconvey
  • Monkey 猴子補(bǔ)丁
  • 數(shù)據(jù)庫(kù) mock
  • travisCI
  • 代碼覆蓋率

TDD

  • 快速實(shí)現(xiàn)功能
  • 再設(shè)計(jì)和重構(gòu)

軟件測(cè)試

在指定的條件下蝗砾,操作程序贫母,發(fā)現(xiàn)程序錯(cuò)誤

單元測(cè)試

對(duì)軟件的組成單元進(jìn)行測(cè)試陈辱,最小單位:函數(shù)

包含三個(gè)步驟:

  • 指定輸入
  • 指定預(yù)期
  • 函數(shù)結(jié)果和指定的預(yù)期比較

指標(biāo):

  • 代碼覆蓋率:運(yùn)行測(cè)試執(zhí)行的代碼占總代碼的行數(shù)

testing 庫(kù)的使用

// Hello ...
func Hello() string {
    return "Hello World"
}
// 傳統(tǒng)測(cè)試
func TestHello(t *testing.T) {
    result := Hello()
    want := "Hello World"
    if result == want {
        t.Logf("Hello() = %v, want %v", result, want)
    } else {
        t.Errorf("Hello() = %v, want %v", result, want)
    }

    want2 := "Hello world"
    if result == want2 {
        t.Logf("Hello() = %v, want %v", result, want)
    } else {
        t.Errorf("Hello() = %v, want %v", result, want)
    }

}

// 表格驅(qū)動(dòng)測(cè)試: 使用匿名結(jié)構(gòu)體故黑,邏輯更清晰
func TestHelloWithTable(t *testing.T) {
    tests := []struct {
        name string
        want string
    }{
        // TODO: Add test cases.
        {
            name: "test for hello",
            want: "Hello World",
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Hello(); got != tt.want {
                t.Errorf("Hello() = %v, want %v", got, tt.want)
            }
        })
    }
}

運(yùn)行:

// mode one 
go test  //  equal to : go test .  執(zhí)行當(dāng)前目錄下的測(cè)試文件

// mode two 
go test ./..   // 加上路徑參數(shù)儿咱,可以執(zhí)行指定目錄下的測(cè)試文件

樣本測(cè)試:

func ExampleHello() {
    fmt.Println(Hello())
    // Output:
    // Hello World
} 

TestMain:

包的測(cè)試運(yùn)行之前執(zhí)行

func TestMain(m *testing.M) {
    fmt.Println("Before ====================")
    code := m.Run()
    fmt.Println("End ====================")
    os.Exit(code)
}

testing 包含下面幾種方法:

  • Log | Logf
  • Error | ErrorF
  • Fatal | FatalF

備注:

  • 文件必須以 ...test.go 結(jié)尾
  • 測(cè)試函數(shù)必須以 TestX... 開(kāi)頭, X 可以是 _ 或者大寫(xiě)字母庭砍,不可以是小寫(xiě)字母或數(shù)字
  • 參數(shù):*testing.T
  • 樣本測(cè)試必須以 Example... 開(kāi)頭,輸入使用注釋的形式
  • TestMain 每個(gè)包只有一個(gè)混埠,參數(shù)為 *testing.M

覆蓋率:

go test -cover

go test -coverprofile=cover.out
go tool cover -html=cover.out -o coverage.html

第三方:goconvey

  • 支持?jǐn)嘌?/li>
  • 支持嵌套
  • 完全兼容內(nèi)置 testing
  • 提供 web UI
func TestAdd_Two(t *testing.T) {
    Convey("test add", t, func() {
        Convey("0 + 0", func() {
            So(Add(0, 0), ShouldEqual, 0)
        })
        Convey("-1 + 0", func() {
            So(Add(-1, 0), ShouldEqual, -1)
        })
    })
}

func TestFloatToString_Two(t *testing.T) {
    Convey("test float to string", t, func() {
        Convey("1.0/3.0", func() {
            result := FloatToString(1.0, 3.0)
            So(result, ShouldContainSubstring, "%")
            So(len(result), ShouldEqual, 6)
            So(result, ShouldEqual, "33.33%")
        })
    })

}

goconvey // 啟動(dòng) web 界面

Monkey 猴子補(bǔ)丁

  • 函數(shù)打樁
  • 過(guò)程打樁
  • 方法打樁
// 函數(shù)
func main() {
    monkey.Patch(fmt.Println, func(a ...interface{}) (n int, err error) {
        s := make([]interface{}, len(a))
        for i, v := range a {
            s[i] = strings.Replace(fmt.Sprint(v), "hell", "*bleep*", -1)
        }
        return fmt.Fprintln(os.Stdout, s...)
    })
    fmt.Println("what the hell?") // what the *bleep*?
}
// 方法
func main() {
    var d *net.Dialer // Has to be a pointer to because `Dial` has a pointer receiver
    monkey.PatchInstanceMethod(reflect.TypeOf(d), "Dial", func(_ *net.Dialer, _, _ string) (net.Conn, error) {
        return nil, fmt.Errorf("no dialing allowed")
    })
    _, err := http.Get("http://google.com")
    fmt.Println(err) // Get http://google.com: no dialing allowed
}
// 過(guò)程
guard := Patch(DestroyResource, func(_ string) {
    
})
defer guard.Unpatch()

使用思路怠缸,被測(cè)函數(shù)中需要使用的其他依賴(lài)函數(shù),進(jìn)行打樁處理钳宪。

sqlmock

對(duì) sql 的執(zhí)行過(guò)程進(jìn)行打樁揭北。

  • 創(chuàng)建模擬連接
  • 編寫(xiě) 原生 sql 語(yǔ)句
  • 編寫(xiě) 返回值 或者 錯(cuò)誤信息
  • 判斷執(zhí)行結(jié)果和預(yù)設(shè)的返回值

Reference

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搔体,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子半醉,更是在濱河造成了極大的恐慌疚俱,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缩多,死亡現(xiàn)場(chǎng)離奇詭異呆奕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)衬吆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)梁钾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人逊抡,你說(shuō)我怎么就攤上這事姆泻。” “怎么了冒嫡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵拇勃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我孝凌,道長(zhǎng)潜秋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任胎许,我火速辦了婚禮,結(jié)果婚禮上罗售,老公的妹妹穿的比我還像新娘辜窑。我一直安慰自己,他們只是感情好寨躁,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布穆碎。 她就那樣靜靜地躺著,像睡著了一般职恳。 火紅的嫁衣襯著肌膚如雪所禀。 梳的紋絲不亂的頭發(fā)上方面,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音色徘,去河邊找鬼恭金。 笑死,一個(gè)胖子當(dāng)著我的面吹牛褂策,可吹牛的內(nèi)容都是我干的横腿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼斤寂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼耿焊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起遍搞,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罗侯,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后溪猿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體钩杰,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年再愈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了榜苫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翎冲,死狀恐怖垂睬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抗悍,我是刑警寧澤驹饺,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站缴渊,受9級(jí)特大地震影響赏壹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衔沼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一蝌借、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧指蚁,春花似錦菩佑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至搓劫,卻和暖如春瞧哟,著一層夾襖步出監(jiān)牢的瞬間混巧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工勤揩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咧党,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓雄可,卻偏偏與公主長(zhǎng)得像凿傅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子数苫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

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

  • Actual Fix Time 實(shí)際修改時(shí)間 Assigned To 被分配給 Closed in Version...
    社會(huì)主義頂梁鹿閱讀 4,240評(píng)論 0 28
  • 序言 要寫(xiě)出好的測(cè)試代碼聪舒,必須精通相關(guān)的測(cè)試框架。對(duì)于Golang的程序員來(lái)說(shuō)虐急,至少需要掌握下面四個(gè)測(cè)試框架: G...
    _張曉龍_閱讀 23,772評(píng)論 7 43
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)箱残、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,120評(píng)論 4 61
  • 在工作中止吁,有時(shí)候會(huì)遇到加密的PDF文件被辑,這種文件一般每次打開(kāi)都需要輸入密碼,而且大都不能進(jìn)行打印和復(fù)制內(nèi)容敬惦。這其實(shí)...
    追思人別後閱讀 6,434評(píng)論 0 0
  • 前幾天回老家俄删。 我踏進(jìn)家門(mén)口的那一霎那宏怔,就看見(jiàn)奶奶沖著我笑,開(kāi)心的不得了畴椰。 我們村里平常日子基本沒(méi)什么人臊诊,很冷清,...
    許沐笙閱讀 842評(píng)論 0 2