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

Golang之模糊測試工具的使用

 更新時(shí)間:2023年03月06日 10:46:26   作者:sheliutao  
本文主要介紹了Golang之模糊測試工具的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

背景

我們經(jīng)常調(diào)侃程序員每天都在寫bug,這確實(shí)是事實(shí),沒有測出bug不代表程序就真的不存在問題。傳統(tǒng)的代碼review、靜態(tài)分析、人工測試和自動(dòng)化的單元測試無法窮盡所有輸入組合,尤其是難以模擬一些隨機(jī)的、邊緣的數(shù)據(jù)。

去年6月,Go官方發(fā)布稱gotip版本已經(jīng)原生支持Fuzzing并開始了公測,將與[Go 1.18版本]一起在2022年中發(fā)布,go-fuzzing至今已經(jīng)發(fā)現(xiàn)了Go標(biāo)準(zhǔn)庫超過200個(gè)bug(https://github.com/dvyukov/go-fuzz#trophies )。即將發(fā)布的[Go 1.18版本]就提供了一個(gè)代碼自測的絕佳工具go-fuzzing。

說到[Go 1.18版本],大家最關(guān)注的應(yīng)該是泛型,但是我個(gè)人覺得go-fuzzing也是其中的一個(gè)亮點(diǎn),Go 1.18將fuzz testing納入了go test工具鏈,與單元測試、性能基準(zhǔn)測試等一起成為了Go原生測試工具鏈中的重要成員。

本次就來說下go-fuzzing這個(gè)工具。

開發(fā)環(huán)境

升級(jí)到Go 1.18
Go 1.18雖然還沒正式發(fā)布,但可以下載RC版本,而且即使你生產(chǎn)環(huán)境用是Go的老版本,你個(gè)人的本地開發(fā)環(huán)境也可以升級(jí)到1.18,還可以使用go-fuzzing更好的自測

go-fuzzing

官方文檔:go fuzzing是通過持續(xù)給一個(gè)程序不同的輸入來自動(dòng)化測試,并通過分析代碼覆蓋率來智能的尋找失敗的例子。這種方法可以盡可能的找到一些邊界問題,親測確實(shí)發(fā)現(xiàn)的都是些平時(shí)比較難發(fā)現(xiàn)的問題。

fuzzing,又叫fuzz testing,中文叫做模糊測試或隨機(jī)測試。其本質(zhì)上是一種自動(dòng)化測試技術(shù),更具體一點(diǎn),它是一種基于隨機(jī)輸入的自動(dòng)化測試技術(shù),常被用于發(fā)現(xiàn)處理用戶輸入的代碼中存在的bug和問題。

fuzz tests規(guī)則

func FuzzFoo(f *testing.F) {
?? ?f.Add(5, "hello")

?? ?f.Fuzz(func(t *testing.T, i int, s string) {
?? ??? ?out, err := Foo(i, s)
?? ??? ?if err != nil && out != "" {
?? ??? ??? ?t.Errorf("%q, %v", out, err)
?? ??? ?}
?? ?})
}
  • 函數(shù)必須是Fuzz開頭,唯一的參數(shù)只有*testing.F,沒有返回值
  • Fuzz tests必須在名為*_test.go的文件下才能執(zhí)行
  • fuzz target是個(gè)方法,它調(diào)用(*testing.F).Fuzz,第一個(gè)參數(shù)是 *testing.T,之后的參數(shù)就是稱之為fuzzing arguments的參數(shù),方法沒有返回值
  • 每個(gè)fuzz test中只能有一個(gè)fuzz target
  • 調(diào)用f.Add()的時(shí)候需要參數(shù)類型跟fuzzing arguments順序和類型都保持一致
  • fuzzing arguments只支持以下類型:
    • int, int8, int16, int32/rune, int64
    • uint, uint8/byte, uint16, uint32, uint64
    • string, []byte
    • float32, float64
    • bool

如何使用go-fuzzing

1、首先要先定義fuzzing arguments,并通過fuzzing arguments寫fuzzing target

2、思考fuzzing target怎么寫,重點(diǎn)是怎么驗(yàn)證結(jié)果的正確性,因?yàn)閒uzzing arguments是隨機(jī)給的,所以要有個(gè)驗(yàn)證結(jié)果的方法

3、遇到失敗的例子怎么去打印出錯(cuò)誤結(jié)果

4、根據(jù)錯(cuò)誤結(jié)果去生成新的測試用例,這個(gè)新的測試用例會(huì)被用來調(diào)試發(fā)現(xiàn)的bug,并且可以留下給CI使用

下面是一個(gè)切片中數(shù)字求和的例子:

// slice_sum.go
func SliceSum(arr []int64) int64 {
? var sum int64

? for _, val := range arr {
? ? if val % 100000 != 0 {
? ? ? sum += val
? ? }
? }

? return sum
}

第一步:定義fuzzing arguments模糊參數(shù)

至少需要給出一個(gè)fuzzing arguments,不然go-fuzzing沒法生成測試代碼。
這是切片中元素求和的方法,那我們可以把切片的元素個(gè)數(shù)n(自行模擬個(gè)數(shù)即可)作為fuzzing arguments,然后go-fuzzing會(huì)根據(jù)運(yùn)行的代碼覆蓋率自動(dòng)生成不同的參數(shù)來模擬測試。

// slice_sum_test.go
func FuzzSliceSum(f *testing.F) {
? // 10,go-fuzzing稱之為語料,10這個(gè)值就是讓go fuzzing冷啟動(dòng)的一個(gè)值,具體多少不重要
? f.Add(10)

? f.Fuzz(func(t *testing.T, n int) {
? ?? ?// 限制20個(gè)元素
? ? n %= 20

? ? // 剩余處理

? })
}

第二步:編寫fuzzing target

重點(diǎn)是編寫可以驗(yàn)證的fuzzing target,不僅要根據(jù)給定的模糊參數(shù)寫出測試代碼,而且還需要生成可以驗(yàn)證結(jié)果正確性的數(shù)據(jù)。
對(duì)這個(gè)切片元素求和的方法來說,就是隨機(jī)生成n個(gè)元素的切片,然后進(jìn)行求和得到正確的結(jié)果。

package fuzz

import (
?? ?"github.com/stretchr/testify/assert"
?? ?"math/rand"
?? ?"testing"
?? ?"time"
)

// slice_sum_test.go
func FuzzSliceSum(f *testing.F) {
? // 初始化隨機(jī)數(shù)種子
? rand.Seed(time.Now().UnixNano())
? // 語料
? f.Add(10)

? f.Fuzz(func(t *testing.T, n int) {
? ? n %= 20

? ? var arr []int64
? ? var expect int64 // 期望值

? ? for i := 0; i < n; i++ {
? ? ? val := rand.Int63() % 1000000
? ? ? arr = append(arr, val)
? ? ? expect += val
? ? }

? ? // 自己求和的結(jié)果和調(diào)用函數(shù)求和的結(jié)果比對(duì)
? ? assert.Equal(t, expect, SliceSum(arr))
? })
}

執(zhí)行模糊測試

?  fuzz go test -fuzz=SliceSum
fuzz: elapsed: 0s, gathering baseline coverage: 0/52 completed
fuzz: elapsed: 0s, gathering baseline coverage: 52/52 completed, now fuzzing with 8 workers
fuzz: elapsed: 0s, execs: 9438 (34179/sec), new interesting: 2 (total: 54)
--- FAIL: FuzzSliceSum (0.28s)
    --- FAIL: FuzzSliceSum (0.00s)
        slice_sum_test.go:32: 
                Error Trace:    slice_sum_test.go:32
                                                        value.go:556
                                                        value.go:339
                                                        fuzz.go:337
                Error:          Not equal: 
                                expected: 5715923
                                actual  : 5315923
                Test:           FuzzSliceSum
    
    Failing input written to testdata/fuzz/FuzzSliceSum/8e8981ffa4ee4d93f475c807563f9d63854a6c913cdfb10a73191549318a2a51
    To re-run:
    go test -run=FuzzSliceSum/8e8981ffa4ee4d93f475c807563f9d63854a6c913cdfb10a73191549318a2a51
FAIL
exit status 1
FAIL    demo/fuzz       0.287s

上面這段輸出,你只能看出預(yù)期值和實(shí)際值不一樣,但是很難分析錯(cuò)誤。

第三步:打印出錯(cuò)誤的例子

上面的錯(cuò)誤輸出,如果能打印出造成錯(cuò)誤的例子的話,就可以直接作為測試用例進(jìn)行單測。我們總不能一個(gè)個(gè)去試吧,而且錯(cuò)誤的例子未必只有一個(gè)。

修改下模糊測試代碼,增加打?。?/p>

package fuzz

import (
?? ?"github.com/stretchr/testify/assert"
?? ?"math/rand"
?? ?"testing"
?? ?"time"
)

// slice_sum_test.go
func FuzzSliceSum(f *testing.F) {
?? ?// 初始化隨機(jī)數(shù)種子
?? ?rand.Seed(time.Now().UnixNano())
?? ?// 語料
?? ?f.Add(10)

?? ?f.Fuzz(func(t *testing.T, n int) {
?? ??? ?n %= 20

?? ??? ?var arr []int64
?? ??? ?var expect int64 // 期望值
?? ??? ?var buf strings.Builder
?? ??? ?buf.WriteString("\n")

?? ??? ?for i := 0; i < n; i++ {
?? ??? ??? ?val := rand.Int63() % 1000000
?? ??? ??? ?arr = append(arr, val)
?? ??? ??? ?expect += val
?? ??? ??? ?buf.WriteString(fmt.Sprintf("%d,\n", val))
?? ??? ?}

?? ??? ?// 自己求和的結(jié)果和調(diào)用函數(shù)求和的結(jié)果比對(duì)
?? ??? ?assert.Equal(t, expect, SliceSum(arr), buf.String())
?? ?})
}

再次執(zhí)行模糊測試

?  fuzz go test -fuzz=SliceSum
fuzz: elapsed: 0s, gathering baseline coverage: 0/47 completed
fuzz: elapsed: 0s, gathering baseline coverage: 47/47 completed, now fuzzing with 8 workers
fuzz: elapsed: 0s, execs: 17109 (42507/sec), new interesting: 2 (total: 49)
--- FAIL: FuzzSliceSum (0.41s)
    --- FAIL: FuzzSliceSum (0.00s)
        slice_sum_test.go:34: 
                Error Trace:    slice_sum_test.go:34
                                                        value.go:556
                                                        value.go:339
                                                        fuzz.go:337
                Error:          Not equal: 
                                expected: 7575516
                                actual  : 7175516
                Test:           FuzzSliceSum
                Messages:       
                                92016,
                                642504,
                                400000,
                                489403,
                                472011,
                                811028,
                                315130,
                                298207,
                                57765,
                                542614,
                                136594,
                                351360,
                                867104,
                                918715,
                                515092,
                                665973,
    
    Failing input written to testdata/fuzz/FuzzSliceSum/9191ba4d7ea5420a9a76661d4e7d6a7a4e69ad4d5d8ef306ff78161a2acf1416
    To re-run:
    go test -run=FuzzSliceSum/9191ba4d7ea5420a9a76661d4e7d6a7a4e69ad4d5d8ef306ff78161a2acf1416
FAIL
exit status 1
FAIL    demo/fuzz       0.413s

第四步:根據(jù)輸出的錯(cuò)誤例子,編寫新的測試用例進(jìn)行單測

// 單測通過后,再執(zhí)行模糊測試,看看有沒有其他邊緣問題出現(xiàn)
func TestSliceSumFuzzCase1(t *testing.T) {
    arr := []int64{
        92016,
        642504,
        400000,
        489403,
        472011,
        811028,
        315130,
        298207,
        57765,
        542614,
        136594,
        351360,
        867104,
        918715,
        515092,
        665973,
    }
    // 期望值從第三步的輸出中獲取
    assert.Equal(t, int64(7575516), SliceSum(arr))
}

這樣就可以很方便的進(jìn)行調(diào)試了,并且能夠增加有效的測試用例進(jìn)行單測,確保這個(gè)bug不會(huì)出現(xiàn)了。

生產(chǎn)環(huán)境項(xiàng)目Go版本問題

線上項(xiàng)目的Go版本不能升級(jí)到1.18怎么辦?

線上的版本不升級(jí)到1.18,但是我們本地開發(fā)升級(jí)沒有問題,可以在文件的頭部增加如下命令注釋:

slice_sum_test.go

//go:build go1.18
// +build go1.18

這樣我們?cè)诰€上不管用哪個(gè)版本都不會(huì)報(bào)錯(cuò),而且我們一般都是在本地進(jìn)行模糊測試

注意:第三行必須是空行,不然就會(huì)變成package的注釋了

有些還無法復(fù)現(xiàn)的問題,比如協(xié)程死鎖,輸出一直在執(zhí)行或者卡住然后過一會(huì)才結(jié)束,這類的長時(shí)間執(zhí)行的模糊測試,我還沒有摸透。如果有大佬知道的話麻煩也告訴我下。

參考
https://github.com/dvyukov/go-fuzz#trophies
https://go.dev/blog/fuzz-beta

到此這篇關(guān)于Golang之模糊測試工具的使用的文章就介紹到這了,更多相關(guān)Golang 模糊測試 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言CSP并發(fā)模型實(shí)現(xiàn)MPG

    Go語言CSP并發(fā)模型實(shí)現(xiàn)MPG

    這篇文章主要為大家介紹了Go語言CSP并發(fā)模型實(shí)現(xiàn)MPG圖文詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Go?Java?算法之字符串解碼示例詳解

    Go?Java?算法之字符串解碼示例詳解

    這篇文章主要為大家介紹了Go?Java?算法之字符串解碼示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go?Web編程添加服務(wù)器錯(cuò)誤和訪問日志

    Go?Web編程添加服務(wù)器錯(cuò)誤和訪問日志

    這篇文章主要為大家介紹了Go?Web編程添加服務(wù)器錯(cuò)誤日志和訪問日志的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Golang實(shí)現(xiàn)JWT身份驗(yàn)證的示例詳解

    Golang實(shí)現(xiàn)JWT身份驗(yàn)證的示例詳解

    JWT(JSON Web Token)是一種開放標(biāo)準(zhǔn)(RFC 7519),用于在網(wǎng)絡(luò)應(yīng)用間安全地傳輸聲明,本文主要為大家詳細(xì)介紹了Golang實(shí)現(xiàn)JWT身份驗(yàn)證的相關(guān)方法,希望對(duì)大家有所幫助
    2024-03-03
  • Golang中Map按照Value大小排序的方法實(shí)例

    Golang中Map按照Value大小排序的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Golang中Map按照Value大小排序的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • 利用Go語言實(shí)現(xiàn)在終端繪制小兔子

    利用Go語言實(shí)現(xiàn)在終端繪制小兔子

    這篇文章主要為大家詳細(xì)介紹了如何利用Go語言實(shí)現(xiàn)在終端繪制小兔子來給大家拜個(gè)早年,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-01-01
  • 在go中進(jìn)行單元測試的案例分享

    在go中進(jìn)行單元測試的案例分享

    這篇文章主要介紹了使用Go進(jìn)行單元測試的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • 談?wù)凣o語言的反射三定律

    談?wù)凣o語言的反射三定律

    本文中,我們將解釋Go語言中反射的運(yùn)作機(jī)制。每個(gè)編程語言的反射模型不大相同,很多語言索性就不支持反射(C、C++)。由于本文是介紹Go語言的,所以當(dāng)我們談到“反射”時(shí),默認(rèn)為是Go語言中的反射。
    2016-08-08
  • GO中高效的將int轉(zhuǎn)換為string的方法與源碼

    GO中高效的將int轉(zhuǎn)換為string的方法與源碼

    本文將從逐步介紹幾種在?Go?中將?int?轉(zhuǎn)換為?string?的常見方法,并重點(diǎn)剖析這幾種方法在性能上的特點(diǎn),另外,還會(huì)重點(diǎn)介紹?FormatInt?高效的算法實(shí)現(xiàn),需要的朋友可以參考下
    2024-01-01
  • Go語言中g(shù)oroutine的使用

    Go語言中g(shù)oroutine的使用

    本文主要介紹了Go語言中g(shù)oroutine的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評(píng)論

陆良县| 清新县| 永兴县| 手游| 东源县| 张家口市| 皋兰县| 大余县| 大安市| 海兴县| 化德县| 朝阳市| 南昌县| 巴塘县| 曲靖市| 固安县| 阿巴嘎旗| 闻喜县| 株洲县| 深泽县| 黑山县| 富顺县| 阳山县| 偃师市| 上犹县| 建瓯市| 石狮市| 本溪市| 汽车| 宽甸| 平凉市| 宁明县| 雷山县| 会昌县| 黄陵县| 永城市| 云林县| 茌平县| 定西市| 额尔古纳市| 金湖县|