Can't range over data set inside Describe block
twhit027 opened this issue · 2 comments
Running table-driven tests with proper descriptions seems buggy (if it's even supported). If you range over test data within a Describe
block, it runs each test with the very last data set in the range, giving invalid test results.
// Example of how it has to be done, but requires less-than optimal scoping
func TestFoo(t *testing.T) {
g := Goblin(t)
tests := []struct {
Description string
Input bool
Output bool
}{
{
Description: `should fail`,
Input: false,
Output: false,
},
{
Description: `should pass`,
Input: false,
Output: true,
},
}
for _, t := range tests {
g.Describe(`foo()`, func() {
g.It(t.Description, func() {
out := foo(t.Input)
g.Assert(out).Equal(t.Output)
})
})
}
}
The above example is how you're required to write table-driven tests, which makes test output ugly by outputting the describe block for every iteration, and also makes scoping of tests more difficult (in terms of After
, Before
, etc). In this case, the first test will fail & the second test will pass, as expected.
// Example of how describe blocks should work, but breaks range
func TestFoo(t *testing.T) {
g := Goblin(t)
g.Describe(`foo()`, func() {
tests := []struct {
Description string
Input bool
Output bool
}{
{
Description: `should fail`,
Input: false,
Output: false,
},
{
Description: `should pass`,
Input: false,
Output: true,
},
}
for _, t := range tests {
g.It(t.Description, func() {
out := foo(t.Input)
g.Assert(out).Equal(t.Output)
})
}
})
}
The second case is how I would expect the nesting of Describe
blocks to work, but in this case, the tests will not run properly. Both tests will pass, running both iterations of the test with the last item in the data set. This is not a valid test result, as we're expecting the first test to fail.
The foo
function in this example just accepts a boolean and inverts it.
func foo(input bool) bool {
return !input
}
Is there any reason why tests using data ranges within a Describe
block should break?
@twhit027 your second example is the correct approach. The reason why it's not working for you is not because of Goblin, but the fact that Go reuses the same variable in loops, check https://github.com/golang/go/wiki/CommonMistakes for further info.
you need to change your range loop
to something like
for _, run := range tests {
var t = run
g.It(t.Description, func() {
out := foo(t.Input)
g.Assert(out).Equal(t.Output)
})
}
Well, TIL! Thanks for the knowledge!