亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go?語(yǔ)言進(jìn)階單元測(cè)試示例詳解

 更新時(shí)間:2023年01月28日 11:02:20   作者:Java星辰  
這篇文章主要為大家介紹了Go?語(yǔ)言進(jìn)階單元測(cè)試示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

本文從單元測(cè)試實(shí)踐角度出發(fā),提升對(duì)代碼質(zhì)量的意識(shí)。

本文內(nèi)容主要包括:?jiǎn)卧獪y(cè)試、Mock測(cè)試、基準(zhǔn)測(cè)試。

測(cè)試

測(cè)試可以提高代碼的質(zhì)量、減少事故的發(fā)生。

測(cè)試又分為:回歸測(cè)試、集成測(cè)試、單元測(cè)試。

回歸測(cè)試是指對(duì)QA手動(dòng)回歸一些特定場(chǎng)景,可以理解為我們說(shuō)的手動(dòng)點(diǎn)點(diǎn)。

集成測(cè)試是指對(duì)系統(tǒng)功能維度做驗(yàn)證,比如對(duì)服務(wù)暴露的接口驗(yàn)證,一般是自動(dòng)化的驗(yàn)證。

單元測(cè)試是指在開(kāi)發(fā)階段,開(kāi)發(fā)者對(duì)單獨(dú)的函數(shù)、模塊做驗(yàn)證,寫(xiě)一些測(cè)試用例。

單元測(cè)試

單元測(cè)試組成部分:輸入、輸出、測(cè)試單元、與期望的校對(duì),測(cè)試單元又包括函數(shù)、接口、模塊、復(fù)雜的聚合函數(shù)等。

通過(guò)單元測(cè)試的輸出再與期望輸出進(jìn)行校對(duì),來(lái)驗(yàn)證代碼的正確性。通過(guò)單元測(cè)試可以保證代碼的質(zhì)量,也可以在一定程度上提升效率,比如通過(guò)運(yùn)行單元測(cè)試可以快速定位到有問(wèn)題的代碼。

規(guī)則

單元測(cè)試的編寫(xiě)有一定的規(guī)則:

  • 所有測(cè)試文件以 _test.go 結(jié)尾
  • 測(cè)試方法名以Test開(kāi)頭,參數(shù)要用testing func TestXxx(t *testing.T)
  • 測(cè)試初始化邏輯放到TestMain
  • 通過(guò)go test命令進(jìn)行測(cè)試

示例

import "testing"
func TestHelloTom(t *testing.T) {
    output := HelloTom()
    expectOutPut := "Tom"
    if output != expectOutPut {
        t.Errorf("Expected %s do not match actual %s", expectOutPut, output)
    }
}
func HelloTom() string {
    return "Jerry"
}

通過(guò)go test命令運(yùn)行得到以下結(jié)果,從測(cè)試結(jié)果里可以看出,我們期望得到的是Tom,但實(shí)際得到的卻是Jerry

--- FAIL: TestHelloTom (0.00s)
helloTom_test.go:9: Expected Tom do not match actual Jerry
FAIL
exit status 1
FAIL    learning/mytesting      0.496s

assert

另外我們可以使用開(kāi)源的assert包,來(lái)代替我們自己的if判斷。

func TestHelloTom(t *testing.T) {
    output := HelloTom()
    expectOutPut := "Tom"
    assert.Equal(t, expectOutPut, output)
}

再次通過(guò)go test命令運(yùn)行得到以下結(jié)果,輸出了更詳細(xì)的堆棧信息。

覆蓋率

如何評(píng)估單元測(cè)試呢?是通過(guò)代碼覆蓋率來(lái)評(píng)估的,評(píng)估的標(biāo)準(zhǔn)包括:

  • 衡量代碼是否經(jīng)過(guò)了足夠的測(cè)試
  • 評(píng)價(jià)項(xiàng)目的測(cè)試水準(zhǔn)
  • 評(píng)估項(xiàng)目是否達(dá)到了高水平的測(cè)試等級(jí)

下面通過(guò)一個(gè)例子來(lái)看下代碼覆蓋率:

// judgepass.go
func JudgePassLine(score int16) bool {
    if score >= 16 {
        return true
    }
    return false
}
// judgepass_test.go
func TestJudgePassLineTrue(t *testing.T) {
    isPass := JudgePassLine(70)
    assert.Equal(t, true, isPass)
}

通過(guò)命令來(lái)看覆蓋率go test judgepass_test.go judgepass.go --cover

輸出結(jié)果為:

ok  command-line-arguments  0.327s  coverage: 66.7% of statements

可以看到,提示出的代碼覆蓋率為66.7%,因?yàn)橹蛔吡艘粋€(gè)if分支。如果要想達(dá)到100%的代碼覆蓋率的話,就要把所有的分支都要覆蓋到。

一般的覆蓋率為50%~60%,較高的覆蓋率要達(dá)到80%+。要注意:測(cè)試分支相互獨(dú)立、要全面覆蓋,測(cè)試單元粒度要足夠小,滿足函數(shù)單一職責(zé)。

依賴

一個(gè)實(shí)際項(xiàng)目不可能只是一個(gè)簡(jiǎn)單的單體函數(shù),肯定會(huì)很復(fù)雜,存在其他的依賴,比如依賴數(shù)據(jù)庫(kù)、redis、文件等外部依賴。

單元測(cè)試一般有兩個(gè)目標(biāo):冪等、穩(wěn)定。

冪等:重復(fù)執(zhí)行一個(gè)用例、調(diào)用一個(gè)接口,返回的結(jié)果是一樣的。

穩(wěn)定:?jiǎn)卧獪y(cè)試是相互隔離的,在任何時(shí)間都能獨(dú)立運(yùn)行。

Mock

如果單元測(cè)試用到數(shù)據(jù)庫(kù)、redis等,在單元測(cè)試?yán)镏苯舆B接會(huì)涉及到網(wǎng)絡(luò)傳輸,這是不穩(wěn)定的,所以要用到Mock機(jī)制。

開(kāi)源Mock框架:github.com/bouk/monkey

這個(gè)Mock包可以對(duì)函數(shù)或方法進(jìn)行打樁,打樁就是用一個(gè)函數(shù)A來(lái)替換一個(gè)函數(shù)B。

monkey的實(shí)現(xiàn)原理主要是在運(yùn)行時(shí),通過(guò)Gounsafe包能夠?qū)?nèi)存中函數(shù)的地址替換為運(yùn)行時(shí)函數(shù)的地址,最終調(diào)用的是打樁函數(shù),從而實(shí)現(xiàn)Mock的功能。

Mock常用方法:Patch、Unpatch

Patch方法有兩個(gè)參數(shù),target為替換的函數(shù)(原函數(shù)),replacement為要替換成的函數(shù)。

func Patch(target, replacement interface{}) *PatchGuard {
    t := reflect.ValueOf(target)
    r := reflect.ValueOf(replacement)
    patchValue(t, r)
    return &PatchGuard{t, r}
}

Unpatch為測(cè)試結(jié)束之后,要把打的樁給卸載掉。

func Unpatch(target interface{}) bool {
    return unpatchValue(reflect.ValueOf(target))
}

下面通過(guò)Mock來(lái)模擬對(duì)文件的操作。

func TestProcessFirstLineWithMock(t *testing.T) {
    monkey.Patch(ReadFirstLine, func() string {
        return "line110"
    })
    defer monkey.Unpatch(ReadFirstLine)
    line := ProcessFirstLine()
    assert.Equal(t, "line000", line)
}
func ReadFirstLine() string {
    open, err := os.Open("log")
    defer open.Close()
    if err != nil {
        return ""
    }
    scanner := bufio.NewScanner(open)
    for scanner.Scan() {
        return scanner.Text()
    }
    return ""
}
func ProcessFirstLine() string {
    line := ReadFirstLine()
    destLine := strings.ReplaceAll(line, "11", "00")
    return destLine
}

該測(cè)試用例對(duì)ProcessFirstLine函數(shù)進(jìn)行測(cè)試,這個(gè)函數(shù)調(diào)用了ReadFirstLine函數(shù),涉及到文件的操作,通過(guò)Mock對(duì)文件的操作進(jìn)行打樁,這樣就避免了其他進(jìn)程對(duì)文件操作的影響。

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

Go還提供了基準(zhǔn)測(cè)試框架,可以測(cè)試一段程序的性能、CPU消耗,可以對(duì)代碼做性能分析,測(cè)試方法與單元測(cè)試類似。

基準(zhǔn)測(cè)試規(guī)則:

  • 基準(zhǔn)測(cè)試以Benchmark為前綴
  • 需要一個(gè)*testing.B類型的參數(shù)b
  • 基準(zhǔn)測(cè)試必須要執(zhí)行b.N次

下面通過(guò)一個(gè)模擬負(fù)載均衡的例子,來(lái)看下基準(zhǔn)測(cè)試:

var ServerIndex [10]int
func InitServerIndex() {
    for i := 0; i < 10; i++ {
        ServerIndex[i] = i + 100
    }
}
func Select() int {
    return ServerIndex[rand.Intn(10)]
}
func BenchmarkSelect(b *testing.B) {
    InitServerIndex()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        Select()
    }
}
func BenchmarkSelectParallel(b *testing.B)  {
    InitServerIndex()
    b.ResetTimer()
    b.RunParallel(func (pb *testing.PB)  {
        for pb.Next() {
            Select()
        }
    })
}

通過(guò)命令 go test -bench=. 運(yùn)行測(cè)試,輸出結(jié)果如下:

goos: darwin
goarch: amd64
pkg: learning/bench
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.70GHz
BenchmarkSelect-8               50264580               23.47 ns/op
BenchmarkSelectParallel-8       13717840               133.4 ns/op
PASS
ok      learning/bench  4.559s

BenchmarkSelect-8 表示對(duì)Select函數(shù)進(jìn)行基準(zhǔn)測(cè)試,數(shù)字8表示 GOMAXPROCS 的值。

23.47 ns/op 表示每次調(diào)用Select函數(shù)耗時(shí)23.47ns。

50264580 這是50264580次調(diào)用的平均值。

字節(jié)開(kāi)源的go框架:github.com/bytedance/g…

引用 Go 語(yǔ)言進(jìn)階與依賴管理

以上就是Go 語(yǔ)言進(jìn)階單元測(cè)試示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Go 語(yǔ)言單元測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語(yǔ)言實(shí)現(xiàn)接口查詢

    go語(yǔ)言實(shí)現(xiàn)接口查詢

    這篇文章主要介紹了go語(yǔ)言實(shí)現(xiàn)接口查詢,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go語(yǔ)言中strings和strconv包示例代碼詳解

    Go語(yǔ)言中strings和strconv包示例代碼詳解

    這篇文章主要介紹了Go語(yǔ)言中strings和strconv包示例代碼詳解 ,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • Go語(yǔ)言結(jié)構(gòu)化日志slog的用法解析

    Go語(yǔ)言結(jié)構(gòu)化日志slog的用法解析

    go?1.21.0?版本引入了一個(gè)新的包?log/slog,該包提供了結(jié)構(gòu)化日志的功能,本文小編就來(lái)和大家聊聊log/slog?包的使用,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Go語(yǔ)言關(guān)于幾種深度拷貝(deepcopy)方法的性能對(duì)比

    Go語(yǔ)言關(guān)于幾種深度拷貝(deepcopy)方法的性能對(duì)比

    這篇文章主要介紹了Go語(yǔ)言關(guān)于幾種深度拷貝(deepcopy)方法的性能對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀

    Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀

    這篇文章主要為大家介紹了Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go語(yǔ)言變量創(chuàng)建的五種方法

    Go語(yǔ)言變量創(chuàng)建的五種方法

    這篇文章主要介紹了Go語(yǔ)言五種變量創(chuàng)建的方法,本文給大家提到了匿名變量的優(yōu)點(diǎn),通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-02-02
  • 基于Go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)易api網(wǎng)關(guān)的示例代碼

    基于Go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)易api網(wǎng)關(guān)的示例代碼

    本文主要介紹了基于Go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)易api網(wǎng)關(guān),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 用golang實(shí)現(xiàn)一個(gè)定時(shí)器任務(wù)隊(duì)列實(shí)例

    用golang實(shí)現(xiàn)一個(gè)定時(shí)器任務(wù)隊(duì)列實(shí)例

    golang中提供了2種定時(shí)器timer和ticker,分別是一次性定時(shí)器和重復(fù)任務(wù)定時(shí)器。這篇文章主要介紹了用golang實(shí)現(xiàn)一個(gè)定時(shí)器任務(wù)隊(duì)列實(shí)例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-05-05
  • Go中的Timer 和 Ticker詳解

    Go中的Timer 和 Ticker詳解

    在日常開(kāi)發(fā)中,我們可能會(huì)遇到需要延遲執(zhí)行或周期性地執(zhí)行一些任務(wù),這個(gè)時(shí)候就需要用到 Go 語(yǔ)言中的定時(shí)器,本文將會(huì)對(duì)這兩種定時(shí)器類型進(jìn)行介紹,感興趣的朋友一起看看吧
    2024-07-07
  • Go語(yǔ)言中獲取IP地址的方法小結(jié)

    Go語(yǔ)言中獲取IP地址的方法小結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中獲取IP地址的常用方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12

最新評(píng)論