The testing package establishes a simple convention for declaring tests for `go test` to find and run:
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(...)
}
}
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
}
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 extension could be the idea of optional setup and teardown methods to be run before and after (respectively) each test method. Ideally, 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--it's call
gunit (as in 'g'-unit). 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 the gunit 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.
Here's an example of this style of fixture implemented using the gunit package. (Please pardon our non-idiomatic use of 'this' for receiver names and "assertion"-like helper functions.)
Thanks for the testing package and thanks for reading!