【Go】Goのテストに入門してみた! ~Fuzzingテスト編~
はじめに
前回は「テーブル駆動ベンチマークテスト」を見ていきました。
今回は「Fuzzingテスト」に入門します。
前回の記事はこちら!
この記事でわかること
- Fuzzingテストの概要や役割
- GoでのFuzzingテストの実施と挙動
- GoでのFuzzingテストの実施ルール
Fuzzingテストとは?
Fuzzingテストとは、意図的に不正なデータや予期しないデータを入れて、システムの脆弱性を検出するテスト手法を指します。
さまざまなテストケースを考慮していると思っていても、予期しないデータの入力に関するテストが漏れていることもあるので、それをカバーすることができます。
Goではtestingパッケージに標準搭載されているので、簡単にfuzzingテストを実行することができます。
Fuzzingテストをやってみよう!
package main
import (
"testing"
"unicode/utf8"
)
func Length(s string) int {
return utf8.RuneCountInString(s)
}
func FuzzLength(f *testing.F) {
seeds := []string{"Hello", "こんにちは", "コンニチハ", "😃😃😃", ""}
for _, seed := range seeds {
f.Add(seed)
}
f.Fuzz(func(t *testing.T, input string) {
got := Length(input)
if got < 0 {
t.Errorf("Length returned negative value: %d", got)
}
want := utf8.RuneCountInString(input)
if got != want {
t.Errorf("Length(%q) = %d, want %d", input, got, want)
}
})
}
以下のように実行することで、Fuzzingテストを実行することができます。
# go test -fuzz=FuzzLength -fuzztime=5s
fuzz: elapsed: 0s, gathering baseline coverage: 0/25 completed
fuzz: elapsed: 0s, gathering baseline coverage: 25/25 completed, now fuzzing with 8 workers
fuzz: elapsed: 3s, execs: 768534 (256090/sec), new interesting: 0 (total: 25)
fuzz: elapsed: 5s, execs: 1288479 (248650/sec), new interesting: 0 (total: 25)
PASS
ok go-test-practice 5.310s
今回は5秒間実施し、1288479件の入力をしたことが書かれています。
最終的にFuzzingテストが成功したことがここからわかります。
GoでのFuzzingテスト実施方法
GoでFuzzingテストを実施するには、いくつかルールがあります。
以下、ルールと実施方法の紹介です。
1. 関数名をFuzzからはじめる
必ず大文字のFからはじめるようにします。
引数には (t *testing.F) を渡すようにします。
返り値はありません。
2. f.Add()でシードコーパスを追加
f.Add() を使ってシードコーパス(初期入力値)を登録します。
Fuzzingテストではこれらの入力からスタートします。
3. f.Fuzz()でテスト実施
f.Fuzz(func(t *testing.T, <引数...>) {...}) という形にします。
引数にはシードコーパスの型を指定するようにしてください。
なお、Go Fuzzingによると、引数には以下の型のみ指定することができます。
The fuzzing arguments can only be the following types:
- string, []byte
- int, int8, int16, int32/rune, int64
- uint, uint8/byte, uint16, uint32, uint64
- float32, float64
- bool
4. 実行方法
Fuzzingテストを実行するには、以下のフラグを用いる必要があります。
-
fuzz:実行するFuzz関数を指定 -
fuzztime:実行時間を指定
※デフォルトでは無制限なのでエラーが発生するまで実行し続ける
まとめ
今回は「Fuzzingテスト」について学びました。
Fuzzingテストには、以下の特徴があることがわかりました。
- 通常のユニットテストでは漏れやすい「予期しない入力」による不具合を検出できる
- Goの標準パッケージに組み込まれており、追加ライブラリなしで利用可能
- シードコーパスを起点に、多様なテストケースを自動生成して検証可能
次回は「httptest」に入門します!
参考
Discussion