我有一些不同的接口实现,以及我想要测试它们的各种因素。最终目标是在不同情况下为不同的实现制作结果网格。
我可以为每种可能的组合编写一个测试,但这会让人筋疲力尽:
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 :(得分:5)
是的,这是可能的。在您的测试文件(xxx_test.go
)中创建自己的TestMain()
函数,并在汇总动态基准案例(struct 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:
在将来的Go版本中, testing.Main()
,testing.MainStart()
和testing.InternalBenchmark
可能会发生变化(或被删除):
内部函数/内部类型但由于它是跨包装而导出;部分或通过执行&#34; go test&#34;命令。
答案 1 :(得分:2)
我认为阅读文档会有所帮助。我忽略了
func Benchmark(f func(b *B)) BenchmarkResult
将运行我的功能,根本不需要任何测试工具。
Benchmark基准测试单一功能。用于创建自定义 不使用&#34; go test&#34;的基准测试命令。
这样我可以遍历我的测试用例并为每种可能性创建一个函数,然后直接运行基准测试。