2015-11-05 70 views
6

我有一個接口的幾個不同的實現,以及我想測試它們的各種因素。最終目標是針對不同情況下的不同實現創建一個網格結果。是否可以動態運行基準測試?

我可以寫爲每個可能的組合測試,但得到疲憊不堪:

func Benchmark_ImplA_N100_X300(b *testing.B){ 
    impl := newImplA(100,300) 
    runBenchmark(b,impl) 
} 

的組合越多我加,我越要複製/粘貼。這很麻煩。

我很樂意做這樣的事情:

tests := []testing.InternalBenchmark{} 
for _, n := range []int{50,100,500,10000}{ 
    for _,x := range []int{300,200}{ 
     for name, gen := range implementations{ 
     impl = gen(n,x) 
     bm := testing.InternalBenchmark{Name: fmt.Sprint(name,x,n)} 
     bm.F = func(b *testing.B){ 
      runBench(b,impl) 
     } 
     tests = append(tests,bm) 
     } 
    } 
} 
testing.RunBenchmarks(anything, tests) 

,這樣我就可以更新組合的列表(一個或多個),和基準會奇蹟般地在所有組合運行。我在main和TestMain中嘗試了類似的東西,並且沒有輸出。我不確定我是否錯誤地使用了它,或者如果測試包只是在做一些有趣的事情。

我真的不在乎go test工具是否可以處理它,或者是否有其他方法。

+0

帶有go的簡單shell腳本:generate也可以工作 – kostya

回答

5

是的,這是可能的。在您的測試文件(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」命令調用。

2

我想讀文檔會有幫助。我忽略

func Benchmark(f func(b *B)) BenchmarkResult

這將運行我的功能wothout不需要任何測試工具都沒有。

基準測試基準單一功能。用於創建不使用「go test」命令的自定義 基準。

這樣我就可以迭代我的測試用例併爲每種可能性創建一個函數,然後直接運行基準測試。

相關問題