Answers:
从Go 1.4开始,您可以实施设置/拆卸(无需在每次测试之前/之后复制功能)。该文档概括这里的主要部分:
TestMain在主goroutine中运行,并且可以在调用m.Run周围进行任何必要的设置和拆卸。然后,应使用m.Run的结果调用os.Exit。
我花了一些时间弄清楚,这意味着如果测试包含一个函数,func TestMain(m *testing.M)
则将调用此函数而不是运行测试。在此函数中,我可以定义测试的运行方式。例如,我可以实现全局设置和拆卸:
func TestMain(m *testing.M) { setup() code := m.Run() shutdown() os.Exit(code) }
可以在此处找到其他两个示例。
最新版本中添加到Go测试框架中的TestMain功能是针对多个测试用例的简单解决方案。TestMain提供了一个全局挂钩,以执行设置和关闭,控制测试环境,在子进程中运行不同的代码,或检查测试代码泄漏的资源。大多数软件包都不需要TestMain,但是在需要的时候,它是一个受欢迎的补充。
lstat $GOROOT/subtests: no such file or directory
这可以通过init()
在_test.go
文件中放置一个函数来实现。这将在init()
功能之前运行。
// package_test.go
package main
func init() {
/* load test data */
}
_test.init()将在包init()函数之前调用。
[TestFixtureSetUp]
属性。
给定一个简单的单元测试功能:
package math
func Sum(a, b int) int {
return a + b
}
您可以使用返回拆卸功能的设置功能对其进行测试。在调用setup()之后,您可以延迟调用teardown()。
package math
import "testing"
func setupTestCase(t *testing.T) func(t *testing.T) {
t.Log("setup test case")
return func(t *testing.T) {
t.Log("teardown test case")
}
}
func setupSubTest(t *testing.T) func(t *testing.T) {
t.Log("setup sub test")
return func(t *testing.T) {
t.Log("teardown sub test")
}
}
func TestAddition(t *testing.T) {
cases := []struct {
name string
a int
b int
expected int
}{
{"add", 2, 2, 4},
{"minus", 0, -2, -2},
{"zero", 0, 0, 0},
}
teardownTestCase := setupTestCase(t)
defer teardownTestCase(t)
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
teardownSubTest := setupSubTest(t)
defer teardownSubTest(t)
result := Sum(tc.a, tc.b)
if result != tc.expected {
t.Fatalf("expected sum %v, but got %v", tc.expected, result)
}
})
}
}
Go测试工具将在Shell控制台中报告日志记录语句:
% go test -v
=== RUN TestAddition
=== RUN TestAddition/add
=== RUN TestAddition/minus
=== RUN TestAddition/zero
--- PASS: TestAddition (0.00s)
math_test.go:6: setup test case
--- PASS: TestAddition/add (0.00s)
math_test.go:13: setup sub test
math_test.go:15: teardown sub test
--- PASS: TestAddition/minus (0.00s)
math_test.go:13: setup sub test
math_test.go:15: teardown sub test
--- PASS: TestAddition/zero (0.00s)
math_test.go:13: setup sub test
math_test.go:15: teardown sub test
math_test.go:8: teardown test case
PASS
ok github.com/kare/go-unit-test-setup-teardown 0.010s
%
您可以使用此方法将一些其他参数传递给设置/拆卸。
通常,进行中的测试与其他语言的编写风格不同。通常,测试功能相对较少,但每个功能都包含一组表驱动的测试用例。请参阅由Go团队之一撰写的本文。
对于表驱动的测试,您只需将所有设置代码放在执行表中指定的各个测试用例的循环之前,然后将所有清除代码放在后面。
如果您在测试功能之间仍然有共享的设置代码,则可以将共享的设置代码提取到函数中,并使用一次(sync.Once
如果很重要的话)请确保它仅执行一次(或者如另一个答案所示,使用use)init()
,但是这样做的缺点是设置即使未运行测试用例也将完成(可能是因为您已使用限制了测试用例go test -run <regexp>
)。
我想说的是,如果您认为需要在不同的测试之间共享设置,这些设置将在一次执行后就确定您是否真的需要它,以及表驱动测试是否会更好。
无耻的插件,我创建了https://github.com/houqp/gtest来帮助解决这个问题。
这是一个简单的示例:
import (
"strings"
"testing"
"github.com/houqp/gtest"
)
type SampleTests struct{}
// Setup and Teardown are invoked per test group run
func (s *SampleTests) Setup(t *testing.T) {}
func (s *SampleTests) Teardown(t *testing.T) {}
// BeforeEach and AfterEach are invoked per test run
func (s *SampleTests) BeforeEach(t *testing.T) {}
func (s *SampleTests) AfterEach(t *testing.T) {}
func (s *SampleTests) SubTestCompare(t *testing.T) {
if 1 != 1 {
t.FailNow()
}
}
func (s *SampleTests) SubTestCheckPrefix(t *testing.T) {
if !strings.HasPrefix("abc", "ab") {
t.FailNow()
}
}
func TestSampleTests(t *testing.T) {
gtest.RunSubTests(t, &SampleTests{})
}
您可以使用一组不同的设置/拆卸例程,在一个包中随心所欲地创建任何测试组。