go 提供的 test 與 benchmark 有3個限制,必需要依照這3個規則來做,這2兩個功能才跑得出來
1. 原始碼檔名必須以『 _b_test.go 』結尾,例如 getData_b_test.go
2. 測試的函數名必須 Test 或 Benchmark 開頭,至於之後的底線則可有可無,例如
func TestgetData1(t *testing.T) {}
func Test_getData1(t *testing.T) {}
func BenchmarkgetData1(b *testing.B) {}
func Benchmark_getData1(b *testing.B) {}
3. 如果要測試整個資料夾內的原始碼,則此資料夾的原始碼不能包含有任何的 main() 函數
如果資料夾裡有 main() 則可改用單一檔案測試
假設現在要開發一個字串串接的功能,go 有3種方式可以串接字串
於是我們寫個測試碼來看看哪一種效率較高
src/strconcat/strconcat.go
(這個是我新開發的功能,不是測試碼,所以檔名不用加 _b_test)
package strconcat
import (
"bytes"
)
func Strconcat1(str1, str2 string) string {
return str1 + str2
}
func Strconcat12(str1, str2 string) {
str1 += str2
}
func Strconcat13(str1, str2 string, str0 *string) {
*str0 = str1 + str2
}
func Strconcat2(str1, str2 string, str0 *[]byte) {
*str0 = []byte(str1)
*str0 = append(*str0, str2...)
}
func Strconcat3(str1, str2 string, str0 *bytes.Buffer) {
str0.WriteString(str1)
str0.WriteString(str2)
}
接下來就要寫一個測試碼來跑這幾個函數
strconcat_b_test.go
(這個測試碼我放在目前工作資料夾內,不需要放在 src 裡)
package bmStrConcat
import (
"bytes"
"fmt"
"testing"
"strconcat"
)
var str1 string = "123456789012345678901234567890"
var str2 string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func TestStrConcat1(t *testing.T) {
str := strconcat.Strconcat1(str1, str2)
if str != "" {
fmt.Println(str)
}
}
func TestStrConcat13(t *testing.T) {
str := ""
strconcat.Strconcat13(str1, str2, &str)
if str != "" {
fmt.Println(str)
}
}
func TestStrConcat2(t *testing.T) {
var str []byte
strconcat.Strconcat2(str1, str2, &str)
if string(str) != "" {
fmt.Println(string(str))
}
}
func TestStrConcat3(t *testing.T) {
var str bytes.Buffer
strconcat.Strconcat3(str1, str2, &str)
if str.Len() >0 {
fmt.Println(str.String())
}
}
func BenchmarkStrConcat1(b *testing.B) {
str0 := ""
for idx := 0; idx < b.N; idx++ {
str0 = strconcat.Strconcat1(str1, str2)
}
fmt.Sprintf("%v", str0)
}
func BenchmarkStrConcat12(b *testing.B) {
for idx := 0; idx < b.N; idx++ {
strconcat.Strconcat12(str1, str2)
}
}
func BenchmarkStrConcat13(b *testing.B) {
str0 := ""
for idx := 0; idx < b.N; idx++ {
strconcat.Strconcat13(str1, str2, &str0)
}
}
func BenchmarkStrConcat2(b *testing.B) {
var str0 []byte
for idx := 0; idx < b.N; idx++ {
strconcat.Strconcat2(str1, str2, &str0)
}
}
func BenchmarkStrConcat3(b *testing.B) {
var str0 bytes.Buffer
for idx := 0; idx < b.N; idx++ {
str0.Reset()
strconcat.Strconcat3(str1, str2, &str0)
}
}
Testxxxxx 的部分主要是查看新函數跑出來的結果是否正確
不一定要像上面那樣寫,也可以改成這樣
var str3 string = str1 + str2
func TestStrConcat1(t *testing.T) {
str := strconcat.Strconcat1(str1, str2)
if str != "" && str == str3 {
fmt.Println("1 OK!")
}
}
func TestStrConcat13(t *testing.T) {
str := ""
strconcat.Strconcat13(str1, str2, &str)
if str != "" && str == str3 {
fmt.Println("13 OK!")
}
}
func TestStrConcat2(t *testing.T) {
var str []byte
strconcat.Strconcat2(str1, str2, &str)
if string(str) == str3 {
fmt.Println("2 OK!")
}
}
func TestStrConcat3(t *testing.T) {
var str bytes.Buffer
strconcat.Strconcat3(str1, str2, &str)
if str.String() == str3 {
fmt.Println("3 OK!")
}
}
Benchmark 的部分就是用迴圈去呼叫新函數...
執行方式跟原來差不多,只是 run 改成 test,並加個選項
$ go test strconcat_b_test.go -bench=.
1 OK!
13 OK!
2 OK!
3 OK!
PASS
BenchmarkStrConcat1-4 10000000 205 ns/op
BenchmarkStrConcat12-4 10000000 218 ns/op
BenchmarkStrConcat13-4 10000000 225 ns/op
BenchmarkStrConcat2-4 5000000 331 ns/op
BenchmarkStrConcat3-4 30000000 56.4 ns/op
ok command-line-arguments 10.918s
-bench=. 表示測試所有的 Textxxx() 與 Benchmarkxxx()
有時候只想看某部分的結果,例如只跑 StrConcat3 的部分,指令可以這樣下
$ go test strconcat_b_test.go -run=.*t3 -bench=.*t3
3 OK!
PASS
BenchmarkStrConcat3-4 30000000 52.4 ns/op
ok command-line-arguments 1.642s
跑 StrConcat2 跟 StrConcat3 的話
$ go test strconcat_b_test.go -run=.*t[23] -bench=.*t[23]
2 OK!
3 OK!
PASS
BenchmarkStrConcat2-4 5000000 315 ns/op
BenchmarkStrConcat3-4 30000000 52.4 ns/op
ok command-line-arguments 3.551s
或是跑 1,3
$ go test strconcat_b_test.go -run=.*t[13] -bench=.*t[13]
1 OK!
13 OK!
3 OK!
PASS
BenchmarkStrConcat1-4 10000000 200 ns/op
BenchmarkStrConcat12-4 10000000 190 ns/op
BenchmarkStrConcat13-4 10000000 199 ns/op
BenchmarkStrConcat3-4 30000000 51.7 ns/op
ok command-line-arguments 8.193s
or
$ go test strconcat_b_test.go -run=.*t[13]$ -bench=.*t[13]$
1 OK!
3 OK!
PASS
BenchmarkStrConcat1-4 10000000 199 ns/op
BenchmarkStrConcat3-4 30000000 52.1 ns/op
ok command-line-arguments 3.834s
t[13]$ 表示結尾,所以 strconcat12, strconcat13 就不會跑
有人說,自己寫 package 之後一定要加 test 的碼
其實看個人啦,如果是要公開給大家用的,那當然就需要囉
最好連 benchmark 的部分都直接提供
如果只是自己用,那就看自己嚕!^_____^