<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 1.18 系列篇(四):一文掌握 Fuzzing 模糊測試

          共 543字,需瀏覽 2分鐘

           ·

          2022-03-27 05:14

          系列導(dǎo)讀


          體驗 Go 1.18(一):如何快速升級安裝 Go 1.18 ?

          體驗 Go 1.18(二):一文掌握泛型用法

          體驗 Go 1.18(三):一文掌握 Go 工作區(qū)模式

          # 1. 什么是模糊測試?

          單元測試,大家應(yīng)該都寫過吧?單元測試,需要開發(fā)者根據(jù)函數(shù)邏輯,給定幾組輸入(入?yún)ⅲ┡c輸出(返回)的數(shù)據(jù),然后 go test 根據(jù)這些數(shù)據(jù)集,調(diào)用函數(shù),若返回值與預(yù)期相符,則說明函數(shù)的單元測試通過。

          但單元測試的代碼,也是由開發(fā)者寫的一段一段代碼,只要是代碼,就會有 BUG,就會有遺漏的場景。

          因此即使單元測試通過,也不代表你的程序沒有問題。

          可見,測試場景的數(shù)據(jù)集對于測試有多重要,而 Fuzzing 模糊測試就是一種用機器根據(jù)已知數(shù)據(jù)源,來自動生成測試數(shù)據(jù)的一種方案。

          本文借用官方的一個例子來講解。

          # 2. 簡單的示例

          在開始之前,先初始化項目

          go?mod?init?github.com/iswbm/fuzz

          然后在該項目中添加 ?main.go,內(nèi)容如下

          package?main

          import?"fmt"

          func?Reverse(s?string)?string?{
          ????b?:=?[]?byte(s)
          ????for?i,?j?:=?0,?len(b)-1;?i?len(b)/2;?i,?j?=?i+1,?j-1?{
          ????????b[i],?b[j]?=?b[j],?b[i]
          ????}
          ????return?string(b)
          }

          func?main()?{
          ????input?:=?"The?quick?brown?fox?jumped?over?the?lazy?dog"
          ????rev?:=?Reverse(input)
          ????doubleRev?:=?Reverse(rev)
          ????fmt.Printf("original:?%q\n",?input)
          ????fmt.Printf("reversed:?%q\n",?rev)
          ????fmt.Printf("reversed?again:?%q\n",?doubleRev)
          }

          現(xiàn)在我們要為 Reverse 函數(shù)編寫單元測試代碼,放在 reverse_test.go,Test 函數(shù)如下

          • 給定了三組數(shù)據(jù)

          • 遍歷這幾組數(shù)據(jù),將 tc.in 做為 Reverses 函數(shù)的入?yún)?zhí)行函數(shù),其返回值跟預(yù)期的 tc.want 做對比

          • 若不相等,則測試不通過~

          package?main

          import?(
          ????"testing"
          )

          func?TestReverse(t?*testing.T)?{
          ????testcases?:=?[]struct?{
          ????????in,?want?string
          ????}{
          ????????{"Hello,?world",?"dlrow?,olleH"},
          ????????{"?",?"?"},
          ????????{"!12345",?"54321!"},
          ????}
          ????for?_,?tc?:=?range?testcases?{
          ????????rev?:=?Reverse(tc.in)
          ????????if?rev?!=?tc.want?{
          ????????????????t.Errorf("Reverse:?%q,?want?%q",?rev,?tc.want)
          ????????}
          ????}
          }

          現(xiàn)在我們執(zhí)行 go test 即是普通的單元測試,輸出 PASS 說明單元測試通過,到目前為止是 Go 1.18 之前的單元測試

          ca6c806f7b53a031f7c6323a908e0592.webp

          然后我們再往 reverse_test.go 中加入 Fuzzing 模糊測試的代碼

          //?記得前面導(dǎo)入?"unicode/utf8"?包

          func?FuzzReverse(f?*testing.F)?{
          ????testcases?:=?[]string{"Hello,?world",?"?",?"!12345"}
          ????for?_,?tc?:=?range?testcases?{
          ????????f.Add(tc)??//?Use?f.Add?to?provide?a?seed?corpus
          ????}
          ????f.Fuzz(func(t?*testing.T,?orig?string)?{
          ????????rev?:=?Reverse(orig)
          ????????doubleRev?:=?Reverse(rev)
          ????????if?orig?!=?doubleRev?{
          ????????????t.Errorf("Before:?%q,?after:?%q",?orig,?doubleRev)
          ????????}
          ????????if?utf8.ValidString(orig)?&&?!utf8.ValidString(rev)?{
          ????????????t.Errorf("Reverse?produced?invalid?UTF-8?string?%q",?rev)
          ????????}
          ????})
          }

          Fuzzing 模糊測試的代碼格式與單元測試很像:

          • 函數(shù)名固定以 Fuzz 開頭(單元測試是以 Test 開頭)

          • 函數(shù)固定以 *testing.F 類型做為入?yún)ⅲ▎卧獪y試是以 *testing.T)

          不一樣的是 Fuzzing 模糊測試,提供兩個函數(shù):

          • t.Add:用于開發(fā)者輸入模糊測試的種子數(shù)據(jù),fuzzing 根據(jù)這些種子數(shù)據(jù),自動隨機生成更多測試數(shù)據(jù)

          • t.Fuzz:開始運行模糊測試,t.Fuzz 的入?yún)⑹且粋€ Fuzz Target 函數(shù)(官方這么叫的),這個 Fuzz Target 函數(shù)的編寫邏輯跟單元測試就一樣了

          在本例子中,F(xiàn)uzz Target 接收 類型為 string 的入?yún)?,做?Reverse 的輸入源,然后利用兩次 Reverse 的結(jié)果應(yīng)與原字符串相等的原理進行測試。

          有了 FuzzReverse 函數(shù)后,就可以使用如下命令進行模糊測試

          go18?test?-fuzz=Fuzz

          通過輸出發(fā)現(xiàn)測試并不順利,Go 1.18 的 Fuzzing 會將導(dǎo)致測試異常的數(shù)據(jù)文件記錄下來,使用 cat 可以查看該測試數(shù)據(jù)

          dbf49caec0452350f1809b7ec60b4240.webp

          記錄下來后,該數(shù)據(jù)就可做為普通單元測試的數(shù)據(jù),此時我們再執(zhí)行 go test 就會引用該數(shù)據(jù),當(dāng)然了,在問題解決之前, go test 會一直報錯

          ece096ada6c973bf42809e91931ce95b.webp

          # 3. 問題排查與解決

          模糊測試幫我們發(fā)現(xiàn)了一個出乎意料的 Bug 場景:在中文里的字符 其實是由3個字節(jié)組成的,如果按照字節(jié)反轉(zhuǎn),反轉(zhuǎn)后得到的就是一個無效的字符串。

          因此為了保證字符串反轉(zhuǎn)后得到的仍然是一個有效的UTF-8編碼的字符串,我們要按照rune進行字符串反轉(zhuǎn)。

          為了更好地方便大家理解中文里的字符 按照rune為維度有多少個rune,以及按照byte反轉(zhuǎn)后得到的結(jié)果長什么樣,我們對代碼做一些修改。

          86ad19f78932ad968504ff28cfb3629e.webp

          改完之后,再次執(zhí)行 go test 就會提示測試成功,說明我們已經(jīng)修復(fù)上面的那個場景的 BUG

          59d445d5068e4a1a435fc8d7a53d07de.webp

          當(dāng)下我們已經(jīng)發(fā)現(xiàn)并修復(fù)了一個 BUG,程序肯定還有更多 BUG 存在,要繼續(xù)尋找可以再次進行模糊測試,重復(fù)上面的步驟即可,這里不再贅述。

          # 4. 更多參數(shù)介紹

          在支持了 Fuzzing 模糊測試后,go test 工具也有了一些新的命令,在這里一并記錄下

          進行模糊測試

          go?test?-fuzz=Fuzz

          只對某個函數(shù)進行模糊測試:使用 -run=Fuzzxxx 或者 -fuzz=Fuzzxxx 指定模糊測試函數(shù),避免執(zhí)行到其他測試函數(shù)

          go18?test?-run=FuzzReverse
          go18?test?-fuzz=FuzzReverse

          測試某個失敗數(shù)據(jù):使用 -run=file 指定數(shù)據(jù)文件

          go?test?-run=FuzzReverse/1fdd0160e6b3dd8f1e6b7a4179b4787e0c014cf9c46c67a863d71e3a0277c213

          指定模糊測試的時間:使用 -fuzztime 指定模糊測試時間或者迭代次數(shù)(默認(rèn)無限期),避免一直在跑測試無法退出

          還有一個 -fuzzminimizetime 參數(shù),看官方文檔的介紹,我沒明白其作用,有知道的還請評論區(qū)分享下

          go?test?-fuzz=Fuzz?-fuzztime?30s

          設(shè)置模糊測試進程數(shù)據(jù):默認(rèn)值是 $GOMAXPROCS,可根據(jù)實際情況進行設(shè)置,避免太占用機器的資源

          go?test?-fuzz=Fuzz?-parallel?4

          # 5. 寫在最后

          模糊測試的存在,并不是為了替代原單元測試,而是為單元測試提供更好的保障,是一個補充方案,而非替代方案。

          單元測試的局限性在于,你只能用預(yù)期的輸入進行測試;模糊測試在發(fā)現(xiàn)暴露出奇怪行為的意外輸入方面非常出色。一個好的模糊測試系統(tǒng)也會對被測試的代碼進行分析,因此它可以有效地產(chǎn)生輸入,從而擴大代碼覆蓋面。

          同時模糊測試的適用場景也比較有限,如果函數(shù)的入?yún)⒉⒉皇窍癖纠械哪菢拥暮唵危ㄗ址?,而是各種對象呢?可能它就無能為力了吧。

          模糊測試的功能,對你有幫助嗎?歡迎你留言分享~


          ? ?

          5a547f3c8bc962c6414138a4ee2e815b.webp
          喜歡明哥文章的同學(xué)歡迎點擊卡片訂閱!

          ???

          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费99视频 | 久久黄色视屏 | 色色一级免费电影 | 69免费观看视频 | 一色综合|