Go中的fuzz模糊測試使用實戰(zhàn)詳解
前言
軟件系統(tǒng)越復雜,測試就越重要。然而手動測試可能會非常費時和乏味。這就是為什么自動化測試變的越來越流行的原因。今天我們來聊一聊自動化測試中的一種測試技術就是fuzz測試,它是一種隨機測試技術,可以幫助發(fā)現(xiàn)軟件系統(tǒng)中的漏洞和錯誤。
Go語言目前已經(jīng)是非常流行的語言了,具有高效、并發(fā)等特性。今天我們淺談使用Go語言進行fuzz測試。從Go1.18開始,Go在其標準工具鏈中支持模糊測試。
什么是fuzz測試
模糊測試 (fuzz testing, fuzzing)是一種軟件測試技術。其核心思想是將自動或半自動生成的隨機數(shù)據(jù)輸入到一個程序中,并監(jiān)視程序異常,如崩潰,斷言(assertion)失敗,以發(fā)現(xiàn)可能的程序錯誤,比如內(nèi)存泄漏。模糊測試常常用于檢測軟件或計算機系統(tǒng)的安全漏洞。
Go語言中的模糊測試
Go為開發(fā)者提供了一套強大的工具,用于實施模糊測試,核心是testing
包中的Fuzz
函數(shù)。通過創(chuàng)建以Fuzz
為前綴的函數(shù),按特定的簽名定義輸入輸出,可以很容易集成模糊測試到我們的Go程序中。
上圖是一個模糊測試的例子,突出顯示了它的主要組件。
模糊測試必須要遵循的規(guī)則:
Fuzz測試必須是一個函數(shù),函數(shù)名必須以"Fuzz"開頭,后面必須是一個大寫字母開頭的名稱,例如"FuzzAdd"。
Fuzz測試函數(shù)必須接受一個*testing.F類型的參數(shù),不能有返回值。
Fuzz測試函數(shù)必須在*_test.go文件中定義才能運行。
Fuzz目標必須是一個方法調(diào)用,第一個參數(shù)必須是*testing.F類型,后面跟隨著fuzz測試的參數(shù)。
每個fuzz測試函數(shù)只能有一個fuzz目標。
所有的種子語料庫條目的類型必須與fuzz測試的參數(shù)類型相同,順序也必須相同。這適用于對Fuzz函數(shù)的調(diào)用以及fuzz測試的testdata/fuzz目錄中的任何語料庫文件。
Fuzz測試的參數(shù)類型只能是以下類型:
string, []byte
int, uint, uintptr, int8, int16, int32, rune, int64, uint8, uint16, uint32, uint64
float32, float64
bool
這些規(guī)則和要求是Go語言fuzz測試的基本要求,遵循這些規(guī)則可以幫助我們編寫有效的fuzz測試并提高測試覆蓋率。
接下來我們通過一些簡單代碼來體驗一下Fuzz test。
代碼編寫
我們創(chuàng)建一個名為fuzz的目錄
> mkdir fuzz > cd fuzz > go mod init example/fuzz > touch main.go
在main.go中我們貼如以下代碼
package main import "fmt" func Add(a, b int) int { return a + b } func main(){ fmt.Printf("Add(1, 2) = %d\n", Add(1, 2)) }
運行代碼
go run . Add(1, 2) = 3
現(xiàn)在代碼正常運行,接下來我們來測試它。
添加單元測試
我們先為Add函數(shù)編寫一個基本的單元測試。
在
fuzz
目錄創(chuàng)建一個文件為add_test.go
。
貼如以下代碼到add_test.go
。
package main import "testing" func TestAdd(t *testing.T) { testcases := []struct { a, b, want int }{ {1, 2, 3}, {0, 0, 0}, {-1, -2, -3}, {1, -2, -1}, } for _, tc := range testcases { got := Add(tc.a, tc.b) if got != tc.want { t.Errorf("Add(%d, %d) == %d, want %d", tc.a, tc.b, got, tc.want) } } }
執(zhí)行單元測試
> go test -v === RUN TestAdd --- PASS: TestAdd (0.00s) PASS ok example/fuzz 0.003s
添加模糊測試
單元測試的局限是我們必須把每個輸入添加到測試中,模糊測試的好處是它提供了你的代碼,并且可能識別你想出的測試用例的邊緣情況。
我們把add_test.go中的單元測試替換為以下內(nèi)容模糊測試。
func FuzzAdd(f *testing.F) { f.Add(1, 2) f.Add(0, 0) f.Add(-1, -2) f.Add(-2, -2) f.Fuzz(func(t *testing.T, a, b int) { got := Add(a, b) if got != a+b { t.Errorf("Add(%d, %d) == %d, want %d", a, b, got, a+b) } t.Logf("Add(%d, %d) == %d", a, b, got) }) }
接下來我們執(zhí)行模糊測試, 通過-run
選項用于指定要運行的測試函數(shù)的正則表達式,-fuzz
選項用于指定要運行的fuzz測試函數(shù)的正則表達式,-fuzztime
選項來控制fuzz測試的持續(xù)時間。
> go test -v -run=FuzzAdd -fuzz=Fuzz -fuzztime 10s === RUN FuzzAdd fuzz: elapsed: 0s, gathering baseline coverage: 0/11 completed fuzz: elapsed: 0s, gathering baseline coverage: 11/11 completed, now fuzzing with 8 workers fuzz: elapsed: 3s, execs: 718882 (239620/sec), new interesting: 1 (total: 12) fuzz: elapsed: 6s, execs: 1444761 (241916/sec), new interesting: 1 (total: 12) fuzz: elapsed: 9s, execs: 2177414 (244215/sec), new interesting: 1 (total: 12) fuzz: elapsed: 10s, execs: 2415524 (216791/sec), new interesting: 1 (total: 12) --- PASS: FuzzAdd (10.10s) === NAME PASS ok example/fuzz 10.106s
總的來說,Go語言內(nèi)置的fuzz測試框架提供了一種方便的方式來進行fuzz測試,它與testing包緊密集成,可以更方便的進行單元測試和fuzz測試。
以上就是Go中的fuzz模糊測試使用實戰(zhàn)詳解的詳細內(nèi)容,更多關于Go fuzz模糊測試的資料請關注腳本之家其它相關文章!