最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go?語言進階單元測試示例詳解

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

前言

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

本文內容主要包括:單元測試、Mock測試、基準測試。

測試

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

測試又分為:回歸測試、集成測試、單元測試。

回歸測試是指對QA手動回歸一些特定場景,可以理解為我們說的手動點點。

集成測試是指對系統(tǒng)功能維度做驗證,比如對服務暴露的接口驗證,一般是自動化的驗證。

單元測試是指在開發(fā)階段,開發(fā)者對單獨的函數(shù)、模塊做驗證,寫一些測試用例。

單元測試

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

通過單元測試的輸出再與期望輸出進行校對,來驗證代碼的正確性。通過單元測試可以保證代碼的質量,也可以在一定程度上提升效率,比如通過運行單元測試可以快速定位到有問題的代碼。

規(guī)則

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

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

示例

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"
}

通過go test命令運行得到以下結果,從測試結果里可以看出,我們期望得到的是Tom,但實際得到的卻是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

另外我們可以使用開源的assert包,來代替我們自己的if判斷。

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

再次通過go test命令運行得到以下結果,輸出了更詳細的堆棧信息。

覆蓋率

如何評估單元測試呢?是通過代碼覆蓋率來評估的,評估的標準包括:

  • 衡量代碼是否經過了足夠的測試
  • 評價項目的測試水準
  • 評估項目是否達到了高水平的測試等級

下面通過一個例子來看下代碼覆蓋率:

// 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)
}

通過命令來看覆蓋率go test judgepass_test.go judgepass.go --cover

輸出結果為:

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

可以看到,提示出的代碼覆蓋率為66.7%,因為只走了一個if分支。如果要想達到100%的代碼覆蓋率的話,就要把所有的分支都要覆蓋到。

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

依賴

一個實際項目不可能只是一個簡單的單體函數(shù),肯定會很復雜,存在其他的依賴,比如依賴數(shù)據庫、redis、文件等外部依賴。

單元測試一般有兩個目標:冪等、穩(wěn)定。

冪等:重復執(zhí)行一個用例、調用一個接口,返回的結果是一樣的。

穩(wěn)定:單元測試是相互隔離的,在任何時間都能獨立運行。

Mock

如果單元測試用到數(shù)據庫、redis等,在單元測試里直接連接會涉及到網絡傳輸,這是不穩(wěn)定的,所以要用到Mock機制。

開源Mock框架:github.com/bouk/monkey

這個Mock包可以對函數(shù)或方法進行打樁,打樁就是用一個函數(shù)A來替換一個函數(shù)B。

monkey的實現(xiàn)原理主要是在運行時,通過Gounsafe包能夠將內存中函數(shù)的地址替換為運行時函數(shù)的地址,最終調用的是打樁函數(shù),從而實現(xiàn)Mock的功能。

Mock常用方法:PatchUnpatch。

Patch方法有兩個參數(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為測試結束之后,要把打的樁給卸載掉。

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

下面通過Mock來模擬對文件的操作。

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
}

該測試用例對ProcessFirstLine函數(shù)進行測試,這個函數(shù)調用了ReadFirstLine函數(shù),涉及到文件的操作,通過Mock對文件的操作進行打樁,這樣就避免了其他進程對文件操作的影響。

基準測試

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

基準測試規(guī)則:

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

下面通過一個模擬負載均衡的例子,來看下基準測試:

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()
        }
    })
}

通過命令 go test -bench=. 運行測試,輸出結果如下:

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 表示對Select函數(shù)進行基準測試,數(shù)字8表示 GOMAXPROCS 的值。

23.47 ns/op 表示每次調用Select函數(shù)耗時23.47ns

50264580 這是50264580次調用的平均值。

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

引用 Go 語言進階與依賴管理

以上就是Go 語言進階單元測試示例詳解的詳細內容,更多關于Go 語言單元測試的資料請關注腳本之家其它相關文章!

相關文章

  • Go語言同步等待組sync.WaitGroup結構體對象方法詳解

    Go語言同步等待組sync.WaitGroup結構體對象方法詳解

    這篇文章主要為大家介紹了Go語言同步等待組sync.WaitGroup結構體對象方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • go實現(xiàn)冒泡排序算法

    go實現(xiàn)冒泡排序算法

    冒泡排序算法是數(shù)據結構中常用的一種算法,本文就介紹了go實現(xiàn)冒泡排序算法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Go?為什么不支持可重入鎖原理解析

    Go?為什么不支持可重入鎖原理解析

    這篇文章主要為大家介紹了Go?為什么不支持可重入鎖原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Go語言中的原子操作使用詳解

    Go語言中的原子操作使用詳解

    這篇文章主要介紹了Go語言中的原子操作使用詳解的相關資料,需要的朋友可以參考下
    2023-08-08
  • go設置多個GOPATH的方式

    go設置多個GOPATH的方式

    這篇文章主要介紹了go設置多個GOPATH的方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • glow工具在命令行讀取Markdown好物分享

    glow工具在命令行讀取Markdown好物分享

    這篇文章主要為大家介紹了一款實用的命令行工具glow,這個CLI工具可以在命令行讀取Markdown,這對于碼農來說非常友好,使用起來也非常舒爽
    2022-07-07
  • Go語言select語句用法示例

    Go語言select語句用法示例

    這篇文章主要為大家介紹了Go語言select語句用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Golang?channel底層實現(xiàn)過程解析(深度好文)

    Golang?channel底層實現(xiàn)過程解析(深度好文)

    Go語言為了方便使用者,提供了簡單、安全的協(xié)程數(shù)據同步和通信機制,這篇文章主要介紹了Golang?channel底層是如何實現(xiàn)的,需要的朋友可以參考下
    2024-07-07
  • 基于Go+WebSocket實現(xiàn)實時通信功能

    基于Go+WebSocket實現(xiàn)實時通信功能

    在互聯(lián)網應用程序中,實時通信是一種非常重要的功能,WebSocket 是一種基于 TCP 的協(xié)議,它允許客戶端和服務器之間進行雙向通信,本文將介紹如何使用 Golang 創(chuàng)建單獨的 WebSocket 會話,以實現(xiàn)實時通信功能,需要的朋友可以參考下
    2023-10-10
  • Golang使用sqlite3數(shù)據庫實現(xiàn)CURD操作

    Golang使用sqlite3數(shù)據庫實現(xiàn)CURD操作

    這篇文章主要為大家詳細介紹了Golang使用sqlite3數(shù)據庫實現(xiàn)CURD操作的相關知識,文中的示例代碼簡潔易懂,有需要的小伙伴可以參考一下
    2025-03-03

最新評論

连城县| 东乡族自治县| 中山市| 潢川县| 天柱县| 泸溪县| 邢台市| 长沙市| 杭州市| 卓资县| 玛多县| 大荔县| 南昌县| 宁晋县| 南华县| 珠海市| 龙江县| 社旗县| 长丰县| 千阳县| 防城港市| 阳朔县| 嘉善县| 中卫市| 泸水县| 武城县| 石屏县| 鹰潭市| 卓尼县| 鄂温| 木兰县| 舟山市| 乾安县| 牡丹江市| 信宜市| 武安市| 穆棱市| 绥芬河市| 贵阳市| 盐津县| 新蔡县|