是的,這是可能的。在您的測試文件(xxx_test.go
)中創建您自己的TestMain()
函數,並且在組裝動態基準情況(結構testing.InternalBenchmark
的值)後,調用testing.Main()
,它可以正確解析命令行標誌,創建並設置testing.M
,並準備和調用testing.RunBenchmarks()
。這樣你的動態基準測試仍然可以運行go test
。
備註:testing.Main()
永遠不會返回,因爲它會調用os.Exit()
。如果您想對基準測試結果執行進一步的日誌記錄和計算,您也可以撥打testing.MainStart()
.Run()
(這是testing.Main()
的作用),並且您可以將M.Run()
返回的退出代碼傳遞到os.Exit()
。
下面是一個完整的測試文件,你可以簡單地運行go test -bench .
。
的輸出是:動態生成的測試基準結果(不同的實施方式的具有不同參數):
testing: warning: no tests to run
PASS
main.EngineA[impl=0, n=50, x=300]-4 100000 16716 ns/op
main.EngineB[impl=1, n=50, x=300]-4 100000 24788 ns/op
main.EngineA[impl=0, n=50, x=200]-4 100000 10764 ns/op
main.EngineB[impl=1, n=50, x=200]-4 100000 16415 ns/op
main.EngineA[impl=0, n=100, x=300]-4 50000 33426 ns/op
main.EngineB[impl=1, n=100, x=300]-4 30000 48466 ns/op
main.EngineA[impl=0, n=100, x=200]-4 50000 20452 ns/op
main.EngineB[impl=1, n=100, x=200]-4 50000 33134 ns/op
main.EngineA[impl=0, n=500, x=300]-4 10000 163087 ns/op
main.EngineB[impl=1, n=500, x=300]-4 5000 238043 ns/op
main.EngineA[impl=0, n=500, x=200]-4 10000 102662 ns/op
main.EngineB[impl=1, n=500, x=200]-4 10000 163113 ns/op
main.EngineA[impl=0, n=1000, x=300]-4 5000 319744 ns/op
main.EngineB[impl=1, n=1000, x=300]-4 3000 512077 ns/op
main.EngineA[impl=0, n=1000, x=200]-4 10000 201036 ns/op
main.EngineB[impl=1, n=1000, x=200]-4 5000 325714 ns/op
ok _/xxx/src/play 27.307s
和源極(一個測試文件,例如dynbench_test.go
):
package main
import (
"fmt"
"testing"
)
type Engine interface {
Calc()
}
type EngineA struct{ n, x int }
func (e EngineA) Calc() {
for i := 0; i < e.n; i++ {
a, b := make([]byte, e.x), make([]byte, e.x)
copy(b, a)
}
}
type EngineB struct{ n, x int }
func (e EngineB) Calc() {
for i := 0; i < e.n*2; i++ {
a, b := make([]byte, e.x/2), make([]byte, e.x/2)
copy(b, a)
}
}
func TestMain(m *testing.M) {
implementations := [](func(n, x int) Engine){
func(n, x int) Engine { return EngineA{n, x} },
func(n, x int) Engine { return EngineB{n, x} },
}
benchmarks := []testing.InternalBenchmark{}
for _, n := range []int{50, 100, 500, 1000} {
for _, x := range []int{300, 200} {
for name, gen := range implementations {
impl := gen(n, x)
bm := testing.InternalBenchmark{
Name: fmt.Sprintf("%T[impl=%d, n=%d, x=%d]", impl, name, n, x)}
bm.F = func(b *testing.B) {
for i := 0; i < b.N; i++ {
impl.Calc()
}
}
benchmarks = append(benchmarks, bm)
}
}
}
anything := func(pat, str string) (bool, error) { return true, nil }
testing.Main(anything, nil, benchmarks, nil)
}
備註#2:
testing.Main()
,testing.MainStart()
和testing.InternalBenchmark
可能會在未來的Go版本中更改(或刪除):
內部函數/內部類型,但由於是交叉包裝而導出;部分或由執行「go test」命令調用。
帶有go的簡單shell腳本:generate也可以工作 – kostya