阅读unit test和fuzz test文档
This commit is contained in:
@@ -191,3 +191,122 @@ fmt.Printf("Generic Sums with Constraint: %v and %v\n",
|
|||||||
SumNumbers(ints),
|
SumNumbers(ints),
|
||||||
SumNumbers(floats))
|
SumNumbers(floats))
|
||||||
```
|
```
|
||||||
|
## Fuzzing
|
||||||
|
如下为一个反转字符串的示例:
|
||||||
|
```go
|
||||||
|
package fuzz
|
||||||
|
|
||||||
|
func Reverse(str string) (ret string, err error) {
|
||||||
|
bytes := []byte(str)
|
||||||
|
for i, j := 0, len(bytes)-1;i<j; i, j = i+1, j-1 {
|
||||||
|
bytes[i], bytes[j] = bytes[j], bytes[i]
|
||||||
|
}
|
||||||
|
ret = string(bytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### unit test编写
|
||||||
|
如果要对上述代码进行单元测试,可以手动在代码中指定测试用例,并对返回值进行断言判断。
|
||||||
|
|
||||||
|
如果想要针对golang文件创建unit test,可以按照如下步骤
|
||||||
|
- 为go文件创建对应的`_test.go`文件,例如`reverse.go`文件,其对应单元测试文件为`reverse_test.go`
|
||||||
|
- 为go文件中想要测试的方法,在`_test.go`文件中创建对应的`TestXxxx`方法,例如对`Reverse`方法,可以创建名为`TestReverse`的测试方法
|
||||||
|
|
||||||
|
在完成上述步骤并且完成测试方法逻辑的编写后,可以调用`go test`命令执行单元测试。
|
||||||
|
|
||||||
|
示例如下所示:
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### fuzz test编写
|
||||||
|
在对功能进行测试时,相对于手动编码测试用例,fuzz能够自动生成用例,并可能触及到手动用例无法触及的边界用例。
|
||||||
|
|
||||||
|
但是,相较于unit text,fuzz无法预知传递的测试参数,也无法预测参数所对应的结果。
|
||||||
|
|
||||||
|
> 在编写fuzz test时,可以将unit test, fuzz test, benchmark都包含在同一个`_test.go`文件中
|
||||||
|
|
||||||
|
在编写fuzz test方法时,步骤如下
|
||||||
|
- fuzz test方法以`FuzzXxx`开头,和`TestXxx`类似
|
||||||
|
- 当调用`f.Add`时,会将参数作为seed添加
|
||||||
|
|
||||||
|
Fuzz test示例如下:
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### 执行fuzz test
|
||||||
|
在编写完上述代码后,首先应该执行`go test`命令,确保作为seed被添加的cases能够通过测试
|
||||||
|
```bash
|
||||||
|
go test
|
||||||
|
```
|
||||||
|
|
||||||
|
> 如果,只想执行指定的测试方法,可以指定`-run`参数,示例如下
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> go test -run=FuzzReverse
|
||||||
|
> ```
|
||||||
|
|
||||||
|
在`go test`执行通过之后,应该执行`go test -fuzz=Fuzz`命令,其会将随机产生的输入作为测试。
|
||||||
|
|
||||||
|
如果存在随机生成的用例测试不通过,会将该用例写入到seed corups文件中,`在下次go test命令被执行时,即使没有指定-fuzz选项,被写入文件中的用例也会被在此执行`。
|
||||||
|
|
||||||
|
> 当通过`go test -fuzz=Fuzz`执行fuzz test时,测试会一直进行,直到被`Ctrl + C`中断。
|
||||||
|
>
|
||||||
|
> 如果要指定fuzz test的时间,可以指定`-fuzztime`选项。
|
||||||
|
>
|
||||||
|
> 示例如下:
|
||||||
|
> ```bash
|
||||||
|
> go test -fuzz=Fuzz -fuzztime 30s
|
||||||
|
> ```
|
||||||
|
|
||||||
|
fuzz test的输出结果示例如下:
|
||||||
|
```powershell
|
||||||
|
PS D:\CodeSpace\demo\fuzz> go test -fuzz=Fuzz -fuzztime 10s
|
||||||
|
fuzz: elapsed: 0s, gathering baseline coverage: 0/56 completed
|
||||||
|
fuzz: elapsed: 0s, gathering baseline coverage: 56/56 completed, now fuzzing with 32 workers
|
||||||
|
fuzz: elapsed: 3s, execs: 3028153 (1008398/sec), new interesting: 2 (total: 58)
|
||||||
|
fuzz: elapsed: 6s, execs: 6197524 (1057429/sec), new interesting: 2 (total: 58)
|
||||||
|
fuzz: elapsed: 9s, execs: 9423882 (1075420/sec), new interesting: 2 (total: 58)
|
||||||
|
fuzz: elapsed: 10s, execs: 10482150 (926639/sec), new interesting: 2 (total: 58)
|
||||||
|
PASS
|
||||||
|
ok git.kazusa.red/asahi/fuzz-demo 10.360s
|
||||||
|
```
|
||||||
|
> #### new interesting
|
||||||
|
> `new interesting`指会扩充code coverage的用例输入,在fuzz test刚开始时,new interesting数量通常会因发现新的代码路径快速增加,然后,会随着时间的推移逐渐减少
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user