为了测试函数,我可以选择将通过选项 -run
运行的函数。
go test -run regex
如果我们有几十个测试用例,则很常见将其放入数组中,以免为每个测试用例编写函数:
cases := []struct {
arg, expected string
} {
{"%a", "[%a]"},
{"%-a", "[%-a]"},
// and many others
}
for _, c := range cases {
res := myfn(c.arg)
if res != c.expected {
t.Errorf("myfn(%q) should return %q, but it returns %q", c.arg, c.expected, res)
}
}
这工作很好,但维护有问题。当我添加一个新的测试用例时,在调试时我想开始一个新的测试用例,但我不能说这样的话:
go test -run TestMyFn.onlyThirdCase
是否有任何优雅的方法,如何将许多测试用例排列在一起并能够选择要运行的测试用例?
最佳答案
使用 Go 1.6(及更低版本)
testing
不直接支持此功能Go 1.6 及以下版本中的包。您必须自己实现它。
但这并不难。您可以使用flag
包以轻松访问命令行参数。
让我们看一个例子。我们定义一个“idx”命令行参数,如果存在该参数,则仅执行该索引处的案例,否则执行所有测试案例。
定义标志:
var idx = flag.Int("idx", -1, "specify case index to run only")
解析命令行标志(实际上,这不是必需的,因为 go test
已经调用了它,但只是为了确定/完整):
func init() {
flag.Parse()
}
使用此参数:
for i, c := range cases {
if *idx != -1 && *idx != i {
println("Skipping idx", i)
continue
}
if res := myfn(c.arg); res != c.expected {
t.Errorf("myfn(%q) should return %q, but it returns %q", c.arg, c.expected, res)
}
}
用 3 个测试用例进行测试:
cases := []struct {
arg, expected string
}{
{"%a", "[%a]"},
{"%-a", "[%-a]"},
{"%+a", "[%+a]"},
}
没有idx
参数:
go test
输出:
PASS
ok play 0.172s
指定索引:
go test -idx=1
输出:
Skipping idx 0
Skipping idx 2
PASS
ok play 0.203s
当然,您可以实现更复杂的过滤逻辑,例如您可以使用 minidx
和 maxidx
标志来运行一定范围内的案例:
var (
minidx = flag.Int("minidx", 0, "min case idx to run")
maxidx = flag.Int("maxidx", -1, "max case idx to run")
)
以及过滤:
if i < *minidx || *maxidx != -1 && i > *maxidx {
println("Skipping idx", i)
continue
}
使用它:
go test -maxidx=1
输出:
Skipping idx 2
PASS
ok play 0.188s
从 Go 1.7 开始
Go 1.7(将于2016年8月18日发布)添加了 subtests and sub-benchmarks 的定义:
The testing package now supports the definition of tests with subtests and benchmarks with sub-benchmarks. This support makes it easy to write table-driven benchmarks and to create hierarchical tests. It also provides a way to share common setup and tear-down code. See the package documentation for details.
有了它,您可以执行以下操作:
func TestFoo(t *testing.T) {
// <setup code>
t.Run("A=1", func(t *testing.T) { ... })
t.Run("A=2", func(t *testing.T) { ... })
t.Run("B=1", func(t *testing.T) { ... })
// <tear-down code>
}
其中子测试名为 "A=1"
、"A=2"
、"B=1"
。
The argument to the -run and -bench command-line flags is a slash-separated list of regular expressions that match each name element in turn. For example:
go test -run Foo # Run top-level tests matching "Foo". go test -run Foo/A= # Run subtests of Foo matching "A=". go test -run /A=1 # Run all subtests of a top-level test matching "A=1".
这对您的案件有何帮助?子测试的名称是字符串值,可以即时生成,例如:
for i, c := range cases {
name := fmt.Sprintf("C=%d", i)
t.Run(name, func(t *testing.T) {
if res := myfn(c.arg); res != c.expected {
t.Errorf("myfn(%q) should return %q, but it returns %q",
c.arg, c.expected, res)
}
})
}
要运行索引 2
处的案例,您可以像这样启动它
go test -run /C=2
或
go test -run TestName/C=2
关于unit-testing - 表驱动测试的子集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38911566/