Using an assertion library with GoDog test framework

Solution 1:

Here's a basic proof-of-concept using Testify:

package bdd
import (
    "fmt"
    "github.com/cucumber/godog"
    "github.com/stretchr/testify/assert"
)
type scenario struct{}
func (_ *scenario) assert(a assertion, expected, actual interface{}, msgAndArgs ...interface{}) error {
    var t asserter
    a(&t, expected, actual, msgAndArgs...)
    return t.err
}
func (sc *scenario) forcedFailure() error {
    return sc.assert(assert.Equal, 1, 2)
}
type assertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool
type asserter struct {
    err error
}
func (a *asserter) Errorf(format string, args ...interface{}) {
    a.err = fmt.Errorf(format, args...)
}
func FeatureContext(s *godog.Suite) {
    var sc scenario
    s.Step("^forced failure$", sc.forcedFailure)
}
Feature: forced failure
  Scenario: fail
    Then forced failure

The key here is implementing Testify's assert.TestingT interface.

Solution 2:

Here's a proof of concept with GoMega:

Register the GoMega Fail Handler before running any tests to have GoMega simply panic with the error message.

gomega.RegisterFailHandler(func(message string, _ ...int) {
    panic(message)
})

Define a step fail handler to recover from any fails.

func failHandler(err *error) {
    if r := recover(); r != nil {
        *err = fmt.Errorf("%s", r)
    }
}

Now at the beginning of every step definition defer running the failHandler like so:

func shouldBeBar(foo string) (err error) {
    defer failHandler(&err)

    Expect(foo).Should(Equal("bar"))

    return err
}

Now if/when the first of our GoMega assertion fails, the step function will run the failHandler and return the GoMega failure message (if there is one). Notice we are using named result parameters to return the error, see How to return a value in a Go function that panics?