国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

手把手教你寫go單元測試

這篇具有很好參考價(jià)值的文章主要介紹了手把手教你寫go單元測試。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

什么是單元測試

? 在 Go 語言中,單元測試是一種測試方法,用于驗(yàn)證代碼的某個(gè)獨(dú)立單元是否按預(yù)期功能,它的目的是確保代碼的每個(gè)組成部分都在獨(dú)立測試的情況下運(yùn)行正常。

? 在我們對(duì)項(xiàng)目新增一個(gè)新功能時(shí),最好就要養(yǎng)成寫單元測試的好習(xí)慣,這樣可以有助于提高我們代碼的質(zhì)量、可維護(hù)性和可靠性。

? 在 Go 中,單元測試的約定是使用標(biāo)準(zhǔn)庫中的?testing?包。測試文件通常以?_test.go?為后綴,然后我們使用?go test ...?配合一些參數(shù)去進(jìn)行測試,Go 測試工具會(huì)自動(dòng)識(shí)別并運(yùn)行這些文件中那點(diǎn)測試樣例。

go test 的兩種模式
1. 本地模式:執(zhí)行當(dāng)前目錄下的所有測試用例

? go test

2. 列表模式:輸入一個(gè)或多個(gè)目錄,執(zhí)行這些目錄下的測試用例

? go test xx/xx

怎么寫單元測試

? 首先,要寫單元測試,那么肯定需要一個(gè)功能函數(shù)。這里我們借用一下之前文章內(nèi)存緩存系統(tǒng)中使用到的一個(gè)功能函數(shù)?ParseSize?,它的功能是將用戶的輸入內(nèi)存大小,轉(zhuǎn)換為字節(jié)數(shù)和對(duì)應(yīng)的字符串表示形式,其中還會(huì)涉及到一些輸入不合法的處理,

? 本文講的是如何寫單元測試,這里 ParseSize 的源碼就直接給大家了,如下:

package util

import (
    "regexp"
    "strconv"
    "strings"
    "time"
)

const (
    B = 1 << (iota * 10)
    KB
    MB
    GB
    TB
    PB
)

const defaultNum = 100

func ParseSize(size string) (int64, string) {
    time.Sleep(time.Nanosecond * 500)

    re, _ := regexp.Compile("[0-9]+")
    unit := string(re.ReplaceAll([]byte(size), []byte("")))
    num, _ := strconv.ParseInt(strings.Replace(size, unit, "", 1), 10, 64)
    unit = strings.ToUpper(unit)

    var byteNum int64 = 0
    switch unit {
    case "B":
        byteNum = num
    case "KB":
        byteNum = num * KB
    case "MB":
        byteNum = num * MB
    case "GB":
        byteNum = num * GB
    case "TB":
        byteNum = num * TB
    case "PB":
        byteNum = num * PB
    default:
        num = 0
    }

    if num == 0 {
        num = 100
        byteNum = num * MB
        unit = "MB"
    }

    sizeStr := strconv.FormatInt(num, 10) + unit
    return byteNum, sizeStr
}

?在項(xiàng)目根目錄下創(chuàng)建 util 目錄,然后創(chuàng)建 util.go 文件,將上面的代碼粘貼進(jìn)去就行了。

? 強(qiáng)調(diào)一點(diǎn),上面的 ParseSize 函數(shù)的開頭,我加了一個(gè)睡眠函數(shù),是因?yàn)槲覀兊?ParseSize 函數(shù)的處理邏輯比較簡單,怕執(zhí)行太快,進(jìn)行測試時(shí)顯示時(shí)間為 0 ,所以加了個(gè)睡眠延遲一點(diǎn)時(shí)間,模擬一些比較耗時(shí)功能函數(shù)。

準(zhǔn)備工作

? 同樣,我們先在 util 包下創(chuàng)建 util_test.go 文件。在寫單元測試的時(shí)候,我們通常有兩種方法,一種是在測試函數(shù)里面構(gòu)建匿名結(jié)構(gòu)體來組織數(shù)據(jù),另一種就是在提前構(gòu)建數(shù)據(jù)。前者就是將構(gòu)建數(shù)據(jù)的邏輯寫在測試函數(shù)里,這里不多做介紹,我們要著重講的是第二種。

? 為了方便,我們先定義一個(gè)結(jié)構(gòu)體,并將其實(shí)例化,用于存放我們的數(shù)據(jù):

// 所有的測試用例放在這里頭
var commTestData []commStruct

type commStruct struct {
    Group         string // 所屬類別
    SizeStr       string // 輸入大小
    ExpectSize    int64  // 預(yù)期輸出大小
    ExpectSizeStr string // 預(yù)期輸出大小字符串類型
}
  • Group:這個(gè)是用于子測試時(shí)分類的依據(jù),關(guān)于子測試后面會(huì)提到,這里先不理會(huì)。
  • SizeStr:是對(duì)應(yīng)于我們的 ParseSize 功能函數(shù)的輸入
  • ExpectSize、ExpectSizeStr:對(duì)應(yīng)于我們的 ParseSize 功能函數(shù)的輸出

? 在單元測試中,也有一個(gè)?func TestMain(m *testing.M)入口函數(shù),功能和用法于平時(shí)我們使用的 main 類似。我們可以在這里面為單元測試做一些準(zhǔn)備工作,但需要注意的是:如果我們沒有寫 TestMain 函數(shù),那么測試工具會(huì)直接調(diào)用我們的測試函數(shù),但如果我們寫了 TestMain 函數(shù),就需要在 TestMain 中通過 m.Run() 顯示地調(diào)用測試用例:

// 測試用例的入口函數(shù):可以為測試做一些準(zhǔn)備工作
func TestMain(m *testing.M) {
    initCommonData()
    m.Run() // 執(zhí)行測試用例
}

func initCommonData() {
    commTestData = []commStruct{
        {"B", "1b", B, "1B"},
        {"B", "100b", 100 * B, "100B"},
        {"KB", "1kb", KB, "1KB"},
        {"KB", "100KB", 100 * KB, "100KB"},
        {"MB", "1Mb", MB, "1MB"},
        {"GB", "10Gb", 10 * GB, "10GB"},
        {"TB", "1tb", TB, "1TB"},
        {"PB", "10PB", 10 * PB, "10PB"},
        {"unknown", "1G", 100 * MB, "100MB"},
    }
}

上面我們通過 TestMain 函數(shù),提前構(gòu)建好了測試所需要的數(shù)據(jù),避免在不同的測試函數(shù)中重復(fù)構(gòu)建測試用例。

功能測試

? 功能測試是一種驗(yàn)證代碼是否按照規(guī)范和需求進(jìn)行工作的測試,它關(guān)注于測試單個(gè)函數(shù)或方法的功能是否正確,以確保其符合預(yù)期的行為。

? 根據(jù)它的定義,我們就大概知道該怎么寫我們的功能測試了。首先功能測試的函數(shù)簽名是這樣的?func TestFunctionName(t *testing.T)。我們直接在函數(shù)里面寫邏輯即可,因?yàn)橛泻芏嘟M測試樣例,所以我們肯定要用 for 循環(huán)將所有的樣例拿出來,然后一一進(jìn)行驗(yàn)證,驗(yàn)證的過程就是將該樣例的輸入拿出來執(zhí)行一遍功能函數(shù),然后將結(jié)果與我們的樣例預(yù)期結(jié)果進(jìn)行比對(duì)即可,如下:

// 功能測試
func TestParseSize(t *testing.T) {
    testData := commTestData
    for _, data := range testData {
        size, sizeStr := ParseSize(data.SizeStr)
        if size != data.ExpectSize || sizeStr != data.ExpectSizeStr {
            t.Errorf("測試結(jié)果不符合預(yù)期:%+v", data)
        }
    }
}

? 這樣我們就寫好了一個(gè)具備基本功能的功能測試代碼了。我們可以通過命令?go test -v?去執(zhí)行,輸出如下:

$  go test -v
=== RUN   TestParseSize
--- PASS: TestParseSize (0.14s)
PASS
ok      main/util       0.178s

? 我們一起來看看這個(gè)輸出:

  1. === RUN TestParseSize:表示正在運(yùn)行名為?TestParseSize?的測試函數(shù)。
  2. --- PASS: TestParseSize (0.14s):表示測試函數(shù)?TestParseSize?成功通過,用時(shí) 0.14 秒。PASS?表示測試通過,FAIL?則表示測試失敗。
  3. PASS:表示整個(gè)測試過程中沒有發(fā)現(xiàn)錯(cuò)誤,所有的測試函數(shù)都成功通過。
  4. ok main/util 0.178s:表示測試包?main/util?成功通過,總用時(shí)為 0.178 秒。

? 下面我們?cè)賮砜纯垂δ軠y試的子測試。

? 功能測試的子測試,又可以叫做并發(fā)測試,我們可以利用它來加快測試的效率。我們下面以測試樣例中的單位,即 group 字段來將測試樣例分個(gè)組:

testData := make(map[string][]commStruct)
for _, item := range commTestData {
    group := item.Group
    _, ok := testData[group]
    if !ok {
        testData[group] = make([]commStruct, 0)
    }
    testData[group] = append(testData[group], item)
}

? 有了數(shù)據(jù),其實(shí)我們的子測試,就相當(dāng)于對(duì)不同組別分別去進(jìn)行測試。

? 所以首先要用一個(gè) for 循環(huán)拿出不同組別的數(shù)據(jù),去分別運(yùn)行,然后在每個(gè)組別運(yùn)行時(shí),去拿出對(duì)應(yīng)組別的數(shù)據(jù)去做驗(yàn)證即可,代碼如下:

func TestParseSizeSub(t *testing.T) {
    if testing.Short() {
        t.Skip("跳過測試用例 TestParseSizeSub")
    }

    // 按照 group 分個(gè)組
    testData := make(map[string][]commStruct)
    for _, item := range commTestData {
        group := item.Group
        _, ok := testData[group]
        if !ok {
            testData[group] = make([]commStruct, 0)
        }
        testData[group] = append(testData[group], item)
    }

    // 分組去測試 測試數(shù)據(jù)
    for k, _ := range testData {
        t.Run(k, func(t *testing.T) {
            // 下面的子測試樣例就會(huì)去并行執(zhí)行:通過睡眠可以看出效果
            t.Parallel()
            for _, data := range testData[k] {
                size, sizeStr := ParseSize(data.SizeStr)
                if size != data.ExpectSize || sizeStr != data.ExpectSizeStr {
                    t.Errorf("測試結(jié)果不符合預(yù)期:%+v", data)
                }
            }
        })
    }
}

? 細(xì)心的小伙伴一定看到了上面有兩個(gè)點(diǎn)是我們沒講的:

  1. if testing.Short()?這個(gè)是做什么的呢?還記得我們上面介紹參數(shù)的時(shí)候說過嗎,這個(gè)參數(shù)是用來避免一些不必要的測試的,所以如果我們的測試不需要,就可以使用 short 參數(shù)跳過這個(gè)子測試。
  2. t.Parallel()?這個(gè)就是我們子測試并行測試的關(guān)鍵了,只有加了這行代碼,我們的子測試才能進(jìn)行并行測試。

? 下面帶大家看看t.Parallel()?是不是真的有效果,我們?cè)谧訙y試代碼中加入一個(gè)睡眠時(shí)間,先把?t.Parallel()?注釋掉:

for k, _ := range testData {
    t.Run(k, func(t *testing.T) {
        //t.Parallel()
        for _, data := range testData[k] {
            time.Sleep(time.Second)
            size, sizeStr := ParseSize(data.SizeStr)
            if size != data.ExpectSize || sizeStr != data.ExpectSizeStr {
                t.Errorf("測試結(jié)果不符合預(yù)期:%+v", data)
            }
        }
    })
}

? 然后執(zhí)行命令?go test -v,可以觀察到子測試的樣例每隔一秒才執(zhí)行一次,最終耗時(shí) 9.367 秒。

$  go test -v
=== RUN   TestParseSize
--- PASS: TestParseSize (0.10s)
=== RUN   TestParseSizeSub
=== RUN   TestParseSizeSub/KB
=== RUN   TestParseSizeSub/MB
=== RUN   TestParseSizeSub/GB
=== RUN   TestParseSizeSub/TB
=== RUN   TestParseSizeSub/PB
=== RUN   TestParseSizeSub/unknown
=== RUN   TestParseSizeSub/B
--- PASS: TestParseSizeSub (9.22s)            
    --- PASS: TestParseSizeSub/KB (2.05s)     
    --- PASS: TestParseSizeSub/MB (1.02s)     
    --- PASS: TestParseSizeSub/GB (1.02s)     
    --- PASS: TestParseSizeSub/TB (1.03s)     
    --- PASS: TestParseSizeSub/PB (1.03s)     
    --- PASS: TestParseSizeSub/unknown (1.03s)
    --- PASS: TestParseSizeSub/B (2.04s)      
PASS
ok      main/util       9.367s

? 我們?cè)侔?t.Parallel()?的注釋去掉,再執(zhí)行?go test -v?觀察一下:

$  go test -v
=== RUN   TestParseSize
--- PASS: TestParseSize (0.14s)
=== RUN   TestParseSizeSub
=== RUN   TestParseSizeSub/unknown
=== PAUSE TestParseSizeSub/unknown
=== RUN   TestParseSizeSub/B
=== PAUSE TestParseSizeSub/B
=== RUN   TestParseSizeSub/KB
=== PAUSE TestParseSizeSub/KB
=== RUN   TestParseSizeSub/MB
=== PAUSE TestParseSizeSub/MB
=== RUN   TestParseSizeSub/GB
=== PAUSE TestParseSizeSub/GB
=== RUN   TestParseSizeSub/TB
=== PAUSE TestParseSizeSub/TB
=== RUN   TestParseSizeSub/PB
=== PAUSE TestParseSizeSub/PB
=== CONT  TestParseSizeSub/unknown
=== CONT  TestParseSizeSub/GB
=== CONT  TestParseSizeSub/PB
=== CONT  TestParseSizeSub/TB
=== CONT  TestParseSizeSub/KB
=== CONT  TestParseSizeSub/MB
=== CONT  TestParseSizeSub/B
--- PASS: TestParseSizeSub (0.00s)
    --- PASS: TestParseSizeSub/TB (1.03s)
    --- PASS: TestParseSizeSub/B (1.03s)
    --- PASS: TestParseSizeSub/MB (1.03s)
    --- PASS: TestParseSizeSub/PB (1.03s)
    --- PASS: TestParseSizeSub/KB (1.03s)
    --- PASS: TestParseSizeSub/unknown (1.03s)
    --- PASS: TestParseSizeSub/GB (1.03s)
PASS
ok      main/util       1.210s

? 會(huì)發(fā)現(xiàn)子測試幾乎是同時(shí)打印出來的信息,最終耗時(shí) 1.120s,這就驗(yàn)證了?t.Parallel()?的作用,也同時(shí)驗(yàn)證了功能測試的子測試的作用。

模糊測試

? 模糊測試是一種隨機(jī)生成輸入數(shù)據(jù)并將其提供給函數(shù)或程序的測試方法,它可以幫助發(fā)現(xiàn)潛在的邊界情況和異常輸入,以檢測代碼的魯棒性。

? 也就是說,模式測試本質(zhì)上也是功能測試,只不過模糊測試的輸入不再是我們提前構(gòu)建好的數(shù)據(jù),而是測試工具根據(jù)我們傳入的參數(shù)類型去幫我們構(gòu)建各種輸入,以此來檢測我們的功能函數(shù)在這種隨機(jī)構(gòu)造的輸入情況下,是否還能照常工作。模糊測試的函數(shù)簽名是func FuzzFunctionName(f *testing.F) {},如下:

func FuzzParseSize(f *testing.F) {
    // 也就是說,模糊測試,本質(zhì)上也是一個(gè)功能測試。
    // 只是輸入的內(nèi)容不再是 data,而是所謂的 a
    f.Fuzz(func(t *testing.T, a string) {
        size, sizeStr := ParseSize(a)
        if size == 0 || sizeStr == "" {
            t.Errorf("輸入異常,導(dǎo)致 parsesize 沒拿到正確結(jié)果")
        }
    })
}

? 然后我們可以通過?go test -fuzz FuzzParseSize?命令開啟模糊測試,輸出如下:

go test -fuzz FuzzParseSize
warning: starting with empty corpus
fuzz: elapsed: 0s, execs: 0 (0/sec), new interesting: 0 (total: 0)
fuzz: elapsed: 3s, execs: 614 (205/sec), new interesting: 7 (total: 7)
fuzz: elapsed: 6s, execs: 4210 (1194/sec), new interesting: 22 (total: 22)
fuzz: elapsed: 9s, execs: 5579 (456/sec), new interesting: 26 (total: 26)
fuzz: elapsed: 12s, execs: 9227 (1221/sec), new interesting: 35 (total: 35)
fuzz: elapsed: 15s, execs: 14480 (1744/sec), new interesting: 44 (total: 44)
fuzz: elapsed: 18s, execs: 16198 (572/sec), new interesting: 49 (total: 49)
......
  1. warning: starting with empty corpus:這是一個(gè)警告,表示開始時(shí)模糊測試的語料庫(corpus)是空的。語料庫是用來保存歷史模式測試時(shí),出現(xiàn)錯(cuò)誤的樣例。
  2. elapsed:經(jīng)過的時(shí)間
  3. execs:執(zhí)行的測試次數(shù)(平均每秒執(zhí)行多少次)
  4. new interesting:新增的隨機(jī)測試輸入個(gè)數(shù)
  5. total:本次測試的的輸入樣例個(gè)數(shù)

? 運(yùn)行模糊測試,你會(huì)發(fā)現(xiàn)根本不會(huì)停,只能主動(dòng)去停止,這也是為什么模糊測試只能同時(shí)測試的原因。

? 還有就是上面提到的預(yù)料庫,在運(yùn)行模糊測試時(shí),如果出現(xiàn)了預(yù)期之外的錯(cuò)誤,那就會(huì)將這個(gè)樣例保存到語料庫中,并且在之后每次的模糊測試都會(huì)去運(yùn)行這些出錯(cuò)的樣例。語料庫也是保存在本地的,會(huì)在根目錄下生成一個(gè)對(duì)應(yīng)的文件去存放。

性能測試

? 最后我們?cè)賮砜纯葱阅軠y試,在進(jìn)行性能測試之前,我們需要先將 ParseSize 函數(shù)中的睡眠函數(shù)關(guān)掉,避免影響我們的性能測試。因?yàn)?code>Sleep()?不僅會(huì)讓程序睡眠,還會(huì)做一些其他處理,會(huì)對(duì)我們的性能測試產(chǎn)生不小的影響。

? 待會(huì)我們也可以做一個(gè)測試,然后進(jìn)行一個(gè)對(duì)比。

? 性能測試寫起來?xiàng)l條框框會(huì)比較多,它的函數(shù)簽名是這樣的?func BenchmarkFunctionName(b *testing.B) {}我們啥也先不管,先來個(gè) for 循環(huán),然后直接調(diào)用我們的 ParseSize 函數(shù):

func BenchmarkParseSize(b *testing.B) {
    for i := 0; i < b.N; i++ {
        ParseSize("1MB")
    }
}

? 這樣,一個(gè)簡易的性能測試就寫完了,我們可以用?go test -bench BenchmarkParseSize,這里先不注釋 ParseSize 中的睡眠函數(shù),我們看看效果:

go test -bench BenchmarkParseSize
goos: windows
goarch: amd64
pkg: main/util
cpu: AMD Ryzen 7 4800H with Radeon Graphics
BenchmarkParseSize-16                100          15301008 ns/op
BenchmarkParseSizeSub/B-16           100          14830110 ns/op
BenchmarkParseSizeSub/KB-16          100          15324944 ns/op
BenchmarkParseSizeSub/MB-16          100          15445510 ns/op
BenchmarkParseSizeSub/GB-16          100          14851633 ns/op
BenchmarkParseSizeSub/TB-16          100          15136910 ns/op
BenchmarkParseSizeSub/PB-16          100          15281375 ns/op
BenchmarkParseSizeSub/unknown-16                     100          15188822 ns/op
PASS
ok      main/util       22.495s

? 再將睡眠函數(shù)注釋掉,運(yùn)行同樣的命令,看看效果:

go test -bench BenchmarkParseSize                                    
goos: windows
goarch: amd64                                       
pkg: main/util                                      
cpu: AMD Ryzen 7 4800H with Radeon Graphics         
BenchmarkParseSize-16             735984              1603 ns/op
BenchmarkParseSizeSub/B-16        704841              1616 ns/op
BenchmarkParseSizeSub/KB-16       750050              1630 ns/op
BenchmarkParseSizeSub/MB-16       748998              1647 ns/op
BenchmarkParseSizeSub/GB-16       635871              1689 ns/op
BenchmarkParseSizeSub/TB-16       769012              1639 ns/op
BenchmarkParseSizeSub/PB-16       748689              1642 ns/op
BenchmarkParseSizeSub/unknown-16                  770593              1620 ns/op
PASS
ok      main/util       19.901s

? 我們先來解釋一下各個(gè)參數(shù)代表什么:

  1. goos: windows?和?goarch: amd64:表示你的操作系統(tǒng)和體系結(jié)構(gòu)。
  2. pkg: main/util:表示正在測試的 Go 包的路徑。
  3. cpu: AMD Ryzen 7 4800H with Radeon Graphics:表示你的 CPU 信息。
  4. BenchmarkParseSize-16 735984 1603 ns/op:表示運(yùn)行了 735984 次,平均每次耗時(shí) 1603 納秒
  5. PASS:表示所有的性能測試都通過
  6. ok main/util 19.901s:表示整個(gè)測試過程消耗了 19.901 秒。

? 可以很明顯的看到,這里兩次測試的平均每次迭代耗時(shí)差了很多個(gè)數(shù)量級(jí),但算上我們的睡眠時(shí)間?time.Sleep(time.Nanosecond * 500),也就 500 ns 而已。之所以會(huì)這樣是因?yàn)?time.Sleep?函數(shù)的調(diào)用對(duì)于測試的結(jié)果會(huì)產(chǎn)生較大的影響,特別是在精度較高的情況,比如我們這里的納米級(jí)別。?time.Sleep?會(huì)導(dǎo)致當(dāng)前 goroutine 掛起,等待指定的時(shí)間再繼續(xù)執(zhí)行。在測試中,這樣的掛起會(huì)導(dǎo)致每次迭代的耗時(shí)相對(duì)較大,從而影響性能測試的結(jié)果。

? 可能會(huì)有人好奇,為什么平均時(shí)長差了很多,但是總耗時(shí)卻差不多。因?yàn)樵?Go 語言的性能測試中,每個(gè)子測試的迭代次數(shù)數(shù)由測試框架自動(dòng)決定的,它會(huì)根據(jù)自己執(zhí)行時(shí)間的變化動(dòng)態(tài)調(diào)整迭代次數(shù),以保證測試結(jié)果的穩(wěn)定性和可靠性。我們也可以自己使用?-benchtime t?參數(shù)來配置自己想要的運(yùn)行次數(shù)和時(shí)間。

? 下面我們?cè)賮砜纯凑f說性能測試的子測試。

? 性能測試的子測試,其實(shí)沒有啥明確的使用場景,我們下面所舉的例子,也只是為了寫性能測試子測試而寫子測試,能夠使用的場景也就是需要分組歸類去測試的數(shù)據(jù),比如 B、KB、MB 等相同單位的一組去測試。

? 這樣做的好處是啥?有人肯定會(huì)覺得,可以像功能測試那樣做并行測試。

? 答案是否定的,性能測試的子測試沒有并行機(jī)制。我個(gè)人覺得這樣的好處就是,可以指定只執(zhí)行對(duì)應(yīng)分組的測試用例,比如我們只需要對(duì)某一個(gè)單位的大小進(jìn)行特殊處理,就可以只去執(zhí)行對(duì)應(yīng)分組的測試用例了。

? 然后我們來看看怎么寫,同樣的,需要先對(duì)我們的測試樣例進(jìn)行分組,然后在用 for 對(duì)不同組別的測試樣例分別去運(yùn)行性能測試函數(shù):

func BenchmarkParseSizeSub(b *testing.B) {
    testData := make(map[string][]commStruct)
    for _, item := range commTestData {
        group := item.Group
        _, ok := testData[group]
        if !ok {
            testData[group] = make([]commStruct, 0)
        }
        testData[group] = append(testData[group], item)
    }

    for k, _ := range testData {
        b.Run(k, func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                ParseSize(testData[k][0].SizeStr)
            }
        })
    }
}

? 上面代碼需要知道的一點(diǎn),就是在每次運(yùn)行?b.Run()?的時(shí)候,for 循環(huán)里的測試次數(shù)是測試工具自動(dòng)決定的,我們只需要調(diào)用就可以了。

? 上面就差不多是性能測試的基本寫法了,只不過在一些情況下,比如我們?cè)诿看螠y試時(shí)需要去進(jìn)行一下其他的數(shù)據(jù)準(zhǔn)備,如果不進(jìn)行一些處理,這些準(zhǔn)備數(shù)據(jù)的時(shí)間就可能會(huì)導(dǎo)致我們的性能測試偏差較大:

for k, _ := range testData {
    b.Run(k, func(b *testing.B) {
        // case1
        preBenchmark()
        for i := 0; i < b.N; i++ {
            // case2
            preBenchmark1()
            ParseSize(testData[k][0].SizeStr)
        }
    })
}

func preBenchmark1() {
    time.Sleep(10 * time.Second)
}

func preBenchmark2() {
    time.Sleep(time.Nanosecond * 500)
}

? 在上述代碼中,我們通過?preBenchmark1?和?preBenchmark2?函數(shù)模擬了準(zhǔn)備數(shù)據(jù)等其他操作的耗時(shí),這里就直接告訴大家解決的方法了:

  • 對(duì)于?case1:可以在數(shù)據(jù)準(zhǔn)備完成后,使用b.ResetTimer()?重置計(jì)時(shí)器
  • 對(duì)于case2:可以在準(zhǔn)備數(shù)據(jù)前使用?b.StopTimer()?將計(jì)時(shí)器暫停,然后在準(zhǔn)備好數(shù)據(jù)后,重新啟動(dòng)計(jì)時(shí)器?b.StartTimer(),這樣就可以減小誤差。
for k, _ := range testData {
    b.Run(k, func(b *testing.B) {
        // for 循環(huán)外,可以通過 b.ResetTimer() 來重置
        preBenchmark1()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            // for 循環(huán)內(nèi),可以通過 b.StopTimer() 和 b.StartTimer() 配合使用,來跳過我們不想統(tǒng)計(jì)的耗時(shí)操作。迫不得已不要使用,測試速度慢
            b.StopTimer()
            preBenchmark2()
            b.StartTimer()
            ParseSize(testData[k][0].SizeStr)
        }
    })
}

? 這里強(qiáng)調(diào)一點(diǎn),上面的解決辦法也只能減緩誤差,并不能真正避免誤差。并且如果你要測試上述代碼的話,記得加上-benchtime?限制一下執(zhí)行次數(shù),否則會(huì)等很久。文章來源地址http://www.zghlxwxcb.cn/news/detail-851267.html

到了這里,關(guān)于手把手教你寫go單元測試的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 正則表達(dá)式詳解(零基礎(chǔ)教學(xué),手把手教你寫正則)

    本篇文章將從零講解什么是正則表達(dá)式,以及正則表達(dá)式的規(guī)則、在python中的應(yīng)用,用通俗易懂的描述方式進(jìn)行零基礎(chǔ)級(jí)別的講解,盡量做到全網(wǎng)最全講解,力求最高質(zhì)量文章,歡迎關(guān)注!點(diǎn)擊目錄可直接進(jìn)行相關(guān)位置跳轉(zhuǎn)。 目錄: 什么是正則? 為什么需要正則? 元字符

    2023年04月08日
    瀏覽(22)
  • 手把手教你寫一個(gè)JSON在線解析的前端網(wǎng)站1

    手把手教你寫一個(gè)JSON在線解析的前端網(wǎng)站1

    作為一名Android開發(fā),經(jīng)常要跟后端同事聯(lián)調(diào)接口,那么總避免不了要格式化接口返回值,將其轉(zhuǎn)換為清晰直觀高亮的UI樣式以及折疊部分內(nèi)容,方便我們查看定位關(guān)鍵的信息。 一直以來都是打開Google 搜索json格式化,然后選擇Google推薦的前三名的網(wǎng)址,比如 bejson網(wǎng)站

    2024年02月08日
    瀏覽(33)
  • 【Java】手把手教你寫學(xué)生信息管理系統(tǒng)(窗口化+MYSQL)

    【Java】手把手教你寫學(xué)生信息管理系統(tǒng)(窗口化+MYSQL)

    ? ? ? ? ? ? (本項(xiàng)目使用到了數(shù)據(jù)庫的可視化軟件DataGrip,需要同學(xué)們自行下載并配置環(huán)境) 首先我們需要在DataGrip中建立一個(gè)student的框架 ????????????????????????????????????????????????????????然后建立一個(gè)studenttable表? ? ? ? ? ? ? ? ? ?

    2024年02月04日
    瀏覽(29)
  • [Kotlin]手把手教你寫一個(gè)安卓APP(第一章注冊(cè)登錄)

    [Kotlin]手把手教你寫一個(gè)安卓APP(第一章注冊(cè)登錄)

    開發(fā)軟件:Android Studio 1.創(chuàng)建項(xiàng)目默認(rèn)選擇Empty Activity ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?點(diǎn)擊Next ?2.生成項(xiàng)目設(shè)置包名選擇開發(fā)語言(這里我用的是kotlin) ?在生成項(xiàng)目后我們要做的就是添加需要的配置打開我們的app目錄下的 buil

    2023年04月23日
    瀏覽(32)
  • 手把手教你寫代碼——基于控制臺(tái)的通訊錄管理系統(tǒng)(單表)

    手把手教你寫代碼——基于控制臺(tái)的通訊錄管理系統(tǒng)(單表)

    本欄目專為入門java學(xué)習(xí)者設(shè)計(jì)的一些簡單的入門項(xiàng)目 本項(xiàng)目為簡單的基于控制臺(tái)的通訊錄管理系統(tǒng),所需要的環(huán)境僅僅為jdk以及mysql(版本不限)!只有一個(gè)簡單的eclipse軟件以及我們的mysql可視化工具(視頻使用navicat) 本項(xiàng)目數(shù)據(jù)庫表僅有一個(gè),單表操作,方便學(xué)習(xí)! 本項(xiàng)

    2024年02月15日
    瀏覽(23)
  • 【Golang項(xiàng)目實(shí)戰(zhàn)】手把手教你寫一個(gè)備忘錄程序|附源碼——建議收藏

    【Golang項(xiàng)目實(shí)戰(zhàn)】手把手教你寫一個(gè)備忘錄程序|附源碼——建議收藏

    博主簡介: 努力學(xué)習(xí)的大一在校計(jì)算機(jī)專業(yè)學(xué)生,熱愛學(xué)習(xí)和創(chuàng)作。目前在學(xué)習(xí)和分享:數(shù)據(jù)結(jié)構(gòu)、Go,Java等相關(guān)知識(shí)。 博主主頁: @是瑤瑤子啦 所屬專欄: Go語言核心編程 近期目標(biāo): 寫好專欄的每一篇文章 前幾天瑤瑤子學(xué)習(xí)了Go語言的基礎(chǔ)語法知識(shí),那么今天我們就寫個(gè)

    2024年02月06日
    瀏覽(28)
  • FPGA之手把手教你寫串口協(xié)議解析(STM32與FPGA數(shù)據(jù)互傳)

    最近趁熱打鐵做了一個(gè)關(guān)于STM32與FPGA通信并且控制高速DA模塊產(chǎn)生不同頻率信號(hào)的正弦波、方波、三角波和鋸齒波的項(xiàng)目,從中收獲到了很多東西,也踩了一些雷和坑,將分為幾篇文章將整個(gè)過程分享出來。 這一次準(zhǔn)備分享的是對(duì)串口數(shù)據(jù)的解析和賦值。解析的數(shù)據(jù)由STM32發(fā)

    2024年02月06日
    瀏覽(28)
  • 數(shù)據(jù)結(jié)構(gòu):線性表————順序表的實(shí)現(xiàn)、項(xiàng)目和OJ題目(手把手教你寫代碼)

    數(shù)據(jù)結(jié)構(gòu):線性表————順序表的實(shí)現(xiàn)、項(xiàng)目和OJ題目(手把手教你寫代碼)

    ?? 個(gè)人主頁: 小新_- ??個(gè)人座右銘:“成功者不是從不失敗的人,而是從不放棄的人!”?? ??歡迎各位→點(diǎn)贊?? + 收藏?? + 留言?? ??所屬專欄:? 話說那些與C++的愛恨情仇 ? 歡迎訂閱,持續(xù)更新中~~~ ?? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ???讓小新帶著你

    2024年04月16日
    瀏覽(235)
  • 基于STM32F103RCT6之手把手教你寫智能家居項(xiàng)目(2)

    基于STM32F103RCT6之手把手教你寫智能家居項(xiàng)目(2)

    ??????? 上一節(jié)我們簡述了智能家居項(xiàng)目,實(shí)現(xiàn)了點(diǎn)燈的相關(guān)代碼編寫,還有WIFI模塊的固件燒錄。 連接什么平臺(tái): ??????? 我們想要遠(yuǎn)程控制家具的開關(guān)和獲取家中的狀態(tài),少不了一個(gè)可以傳輸數(shù)據(jù)的云平臺(tái)。我認(rèn)為易監(jiān)控是一個(gè)簡單好用的云平臺(tái)。 怎么連接平臺(tái):

    2024年02月20日
    瀏覽(909)
  • 【C語言】手把手教你文件操作

    【C語言】手把手教你文件操作

    程序運(yùn)行時(shí),數(shù)據(jù)存放在內(nèi)存中,而當(dāng)程序退出后,數(shù)據(jù)也就不復(fù)存在。 想做到數(shù)據(jù)持久化,我們可以把數(shù)據(jù)存放在硬盤,或者放到數(shù)據(jù)庫里。而在C語言中,利用文件操作,就可以將數(shù)據(jù)存放在硬盤上。 讀寫之前應(yīng)該先打開文件,使用結(jié)束之后要關(guān)閉文件。 fopen 函數(shù)用于打

    2024年02月05日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包