【发布时间】:2019-11-27 18:36:22
【问题描述】:
是否可以从非测试 go 文件中调用测试函数来开始执行测试?
例如,我有一个测试功能:
package API
import "testing"
func TestAPI(t *testing.T) {
...
}
我需要从非测试 go 文件中调用它。
package main
import "../API"
API.TestAPI()
我可以这样做吗?
【问题讨论】:
标签: go
是否可以从非测试 go 文件中调用测试函数来开始执行测试?
例如,我有一个测试功能:
package API
import "testing"
func TestAPI(t *testing.T) {
...
}
我需要从非测试 go 文件中调用它。
package main
import "../API"
API.TestAPI()
我可以这样做吗?
【问题讨论】:
标签: go
Go 中有一些很棒的测试模式。不幸的是,您尝试测试的方式行不通。
您的单元测试应该使用命令go test <pkg 运行。永远不要从代码本身中调用测试。
Go 中通常有两种主要的单元测试形式——黑盒单元测试和白盒单元测试。
白盒测试:从内部测试未导出函数 自己打包。
黑盒测试:从外部测试导出的函数 包,模拟其他包将如何与之交互。
如果我有一个包,example,我想测试它。有一个简单的 exported 函数,它对提供的数字列表求和。 Sum 函数还使用了一个未导出实用程序函数。
example.go
package example
func Sum(nums ...int) int {
sum := 0
for _, num := range nums {
sum = add(sum, num)
}
return sum
}
func add(a, b int) int {
return a + b
}
example_test.go:黑盒测试
请注意,我正在测试 example 包,但测试位于 example_test 包中。添加_test 可以让Go 编译器满意,并让它知道这是example 的测试包。在这里,我们只能访问导出的变量和函数,以便我们测试外部包在导入和使用我们的example 包时会遇到的行为。
package example_test
import (
"testing"
"example"
)
func TestSum(t *testing.T) {
tests := []struct {
nums []int
sum int
}{
{nums: []int{1, 2, 3}, sum: 6},
{nums: []int{2, 3, 4}, sum: 9},
}
for _, test := range tests {
s := example.Sum(test.nums...)
if s != test.sum {
t.FailNow()
}
}
}
example_internal_test.go:白盒测试
请注意,我正在测试example 包,并且该测试也位于example 包中。这允许单元测试访问未导出的变量和函数。
package example
import "testing"
func TestAdd(t *testing.T) {
tests := []struct {
a int
b int
sum int
}{
{a: 1, b: 2, sum: 3},
{a: 3, b: 4, sum: 7},
}
for _, test := range tests {
s := add(test.a, test.b)
if s != test.sum {
t.FailNow()
}
}
}
我希望这能让您更好地了解 Go 的测试框架是如何设置和使用的。为简单起见,我没有在示例中使用任何外部库,尽管github.com/stretchr/testify 是一个非常流行且功能强大的包来帮助进行单元测试。
【讨论】:
您正在尝试是可能的,但不建议这样做,因为它取决于 Go 的 testing 库的内部细节,这些细节不在 Go 1 兼容保证范围内,这意味着您很可能必须为每个 Go 版本调整这种方法。
您应该很少(如果有的话)尝试此操作。我这样做过一次,我希望能够作为正常测试运行的一套 API 集成测试,也可以从 CLI 工具运行,以测试 API 的第三方实现。现在我已经做到了,我不确定我是否会再做一次。我可能会寻找不同的方法。
但如果你不能被劝阻,那么你需要做的是:
您的测试必须不在名为 *_test.go 的文件中定义。此类文件被排除在正常编译之外。
对于您的正常测试用例,您必须触发测试从名为 *_test.go 的文件运行。
您必须手动编排非测试用例中的测试。
详细说明:
将测试放在非测试文件中。 testing 包只是一个标准包,因此可以轻松地包含在您需要的任何地方:
foo.go
package foo
import "testing"
func SomethingTest(t *testing.T) {
// your tests
}
从*_test.go 文件运行测试:
foo_test.go
func TestSomething(t *testing.T) {
SomethingTest(t)
}
并从您的非测试文件中运行测试。在这里,您处于危险的境地,因为它需要使用不受 Go 1 兼容性保证保护的方法。您需要调用 testing.MainStart 方法,并使用手动制作的测试列表。
这也需要实现你自己的testing.testDeps 版本,它是私有的,但是一个接口,很容易实现。你可以看到我的 Go 1.9 实现here。
tests := []testing.InternalTest{
{
Name: "TestSomething",
f: SomethingTest,
},
}
m := testing.MainStart(MyTestDeps, tests, nil, nil)
os.Exit(m.Run())
这是一个非常简化的示例,并不完整。但我希望它能让你走上正确的道路。
【讨论】: