Да, это возможно. В тестовом файле (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:
testing.Main()
, testing.MainStart()
и testing.InternalBenchmark
может быть изменен (или удален) в следующем выпуске Go:
Внутренняя функция/внутренний тип, но экспортируется, поскольку это кросс-пакет; часть или вызвана выполнением команды «go test».
простой скрипт оболочки с go: generate может работать также – kostya