Open
Description
When writing tests in BDD style using subtests it's often necessary to invoke some common code before or after a subtest. In the example below we call beforeRun
in the first place of subtests 1 and 2, otherwise the subtests would affect the outcome of each other:
type CoffeeMachine struct {
on bool
}
func (a *CoffeeMachine) TurnOn() error {
if a.on {
return fmt.Errorf("aready on")
}
a.on = true
return nil
}
func (a *CoffeeMachine) MakeCoffee() error {
if !a.on {
return fmt.Errorf("power is off")
}
return nil
}
func TestCoffeeMachine(t *testing.T) {
// 0
t.Run("given a new coffee machine", func(t *testing.T) {
var a CoffeeMachine
beforeRun := func(t *testing.T) {
a = CoffeeMachine{}
}
// 1
t.Run("it could be turned on", func(t *testing.T) {
beforeRun(t)
err := a.TurnOn()
assert.NoError(t, err)
// 1.1
t.Run("it could not be turned on again", func(t *testing.T) {
err := a.TurnOn()
assert.Error(t, err)
})
// 1.2
t.Run("it makes a coffee", func(t *testing.T) {
err := a.MakeCoffee()
assert.NoError(t, err)
})
})
// 2
t.Run("MakeCoffee fails because it's not turned on", func(t *testing.T) {
beforeRun(t)
err := a.MakeCoffee()
assert.Error(t, err)
})
})
}
It would be nice instead, if the testing package could invoke a specific function by itself before/after direct subtests of the parent where it's configured:
func TestCoffeeMachine(t *testing.T) {
// 0
t.Run("given a new coffee machine", func(t *testing.T) {
var a CoffeeMachine
// a new proposed method for testing.T
t.BeforeRun(func(t *testing.T) {
a = CoffeeMachine{}
})
// 1
t.Run("it could be turned on", func(t *testing.T) {
// the functor passed to BeforeRun is called before we reach this point
err := a.TurnOn()
assert.NoError(t, err)
// 1.1
t.Run("it could not be turned on again", func(t *testing.T) {
err := a.TurnOn()
assert.Error(t, err)
})
// 1.2
t.Run("it makes a coffee", func(t *testing.T) {
err := a.MakeCoffee()
assert.NoError(t, err)
})
})
// 2
t.Run("MakeCoffee fails because it's not turned on", func(t *testing.T) {
// the functor passed to BeforeRun is called before we reach this point
err := a.MakeCoffee()
assert.Error(t, err)
})
})
}
The points against of the explicit beforeRun(t)
calls from subtests are the following:
- it can simply be skipped by mistake
- it can be called from a wrong level by mistake
So I propose to add func (t *T) BeforeRun(func(t *testing.T)
and func (t *T) AfterRun(func(t *testing.T)
methods which should be invoked by the testing package before/after direct subtests of the parent where it's configured.
Metadata
Metadata
Assignees
Type
Projects
Status
Incoming