-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
The testing package establishes a simple convention for declaring tests for go test to find and run:
func TestXxx(t *testing.T) {
}
Consider this group of example test functions:
func TestFoo(*testing.T) {
state = NewSomethingToTest()
if !state.Foo() {
t.Error(...)
}
}
func TestBar(*testing.T) {
state = NewSomethingToTest()
if !state.Bar() {
t.Error(...)
}
}
func TestBaz(*testing.T) {
state = NewSomethingToTest()
if !state.Baz() {
t.Error(...)
}
}
Provided all goes well, running the tests produces something akin to the following output:
$ go test -v
=== RUN TestFoo
--- PASS: TestFoo (0.01s)
=== RUN TestBar
--- PASS: TestBar (0.02s)
=== RUN TestBaz
--- PASS: TestBaz (0.03s)
PASS
ok my/package/name 0.06s
I'd like to see the following convention also allowed:
type MyTests struct {
*testing.T // embed all the goodness offered by *testing.T (t.Error(), t.Skip, etc...)
state SomethingToTest
}
// Setup would be invoked before each Test method on *MyTests.
func (t *MyTests) Setup() {
t.state = NewSomethingToTest()
}
func (t *MyTests) TestFoo() {
if !t.state.Foo() {
t.Error(...)
}
}
func (t *MyTests) TestBar() {
if !t.state.Bar() {
t.Error(...)
}
}
func (t *MyTests) TestBaz() {
if !t.state.Baz() {
t.Error(...)
}
}
Which could produce something like the following output:
$ go test -v
=== RUN Test_MyFixture_Foo
--- PASS: Test_MyFixture_Foo (0.01s)
=== RUN Test_MyFixture_Bar
--- PASS: Test_MyFixture_Bar (0.02s)
=== RUN Test_MyFixture_Baz
--- PASS: Test_MyFixture_Baz (0.03s)
PASS
ok my/package/name 0.06s
Included in this addition (as seen in the example above) would be optionally defined setup and teardown methods to be run before and after (respectively) each test method. (In an ideal implementation each test method would be invoked on a unique instance of MyFixture which is created just for that test method.)
I've already implemented something very close to this. The only thing I don't like about my implementation is that in order for go test to find and run the test methods on the test structs, I have to run go generate first, which calls a command I've also written as part of that project which generates compatible Test functions that instantiate the struct and then call the test methods (along with defined setups and teardowns). I'd like to be rid of the go generate step to achieve struct-scoped test methods. One benefit here is that you can trivially extract other useful methods on that struct that are called from the test methods. It is trivial because you don't have to pass in any local state to those methods--all the state is already declared on the struct as fields.
Further reading and examples:
- more complete example
- gunit project readme (the project mentioned above)
- gunit examples
Thanks for providing us the testing package and go test, and for your consideration of this idea.