Skip to content

Commit

Permalink
Merge pull request #289 from cucumber/assert-godogs-example
Browse files Browse the repository at this point in the history
Added an example for how to use assertion pkgs like testify with godog
  • Loading branch information
lonnblad authored May 3, 2020
2 parents 075d624 + bfee72d commit 521a968
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 2 deletions.
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ themselves from costly regressions.

## Example

The following example can be [found
here](/_examples/godogs).
The following example can be [found here](/_examples/godogs).

### Step 1

Expand Down Expand Up @@ -345,6 +344,40 @@ is one of the following:
- `@wip && ~@new` - run wip scenarios, but exclude new
- `@wip,@undone` - run wip or undone scenarios

### Using assertion packages like testify with Godog
A more extensive example can be [found here](/_examples/assert-godogs).

``` go
/* file: $GOPATH/src/assert-godogs/godogs_test.go */

func thereShouldBeRemaining(remaining int) error {
return assertExpectedAndActual(
assert.Equal, Godogs, remaining,
"Expected %d godogs to be remaining, but there is %d", remaining, Godogs,
)
}

// assertExpectedAndActual is a helper function to allow the step function to call
// assertion functions where you want to compare an expected and an actual value.
func assertExpectedAndActual(a expectedAndActualAssertion, expected, actual interface{}, msgAndArgs ...interface{}) error {
var t asserter
a(&t, expected, actual, msgAndArgs...)
return t.err
}

type expectedAndActualAssertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool

// asserter is used to be able to retrieve the error reported by the called assertion
type asserter struct {
err error
}

// Errorf is used by the called assertion to report an error
func (a *asserter) Errorf(format string, args ...interface{}) {
a.err = fmt.Errorf(format, args...)
}
```

### Configure common options for godog CLI

There are no global options or configuration files. Alias your common or
Expand Down
15 changes: 15 additions & 0 deletions _examples/assert-godogs/features/godogs.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# file: $GOPATH/godogs/features/godogs.feature
Feature: eat godogs
In order to be happy
As a hungry gopher
I need to be able to eat godogs

Scenario: Eat 5 out of 12
Given there are 12 godogs
When I eat 4
Then there should be 7 remaining

Scenario: Eat 12 out of 12
Given there are 12 godogs
When I eat 11
Then there should be none remaining
7 changes: 7 additions & 0 deletions _examples/assert-godogs/godogs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* file: $GOPATH/src/godogs/godogs.go */
package main

// Godogs available to eat
var Godogs int

func main() { /* usual main func */ }
108 changes: 108 additions & 0 deletions _examples/assert-godogs/godogs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* file: $GOPATH/src/assert-godogs/godogs_test.go */
package main

import (
"flag"
"fmt"
"os"
"testing"

"github.com/cucumber/godog"
"github.com/cucumber/godog/colors"
messages "github.com/cucumber/messages-go/v10"
"github.com/stretchr/testify/assert"
)

var opt = godog.Options{Output: colors.Colored(os.Stdout)}

func init() {
godog.BindFlags("godog.", flag.CommandLine, &opt)
}

func TestMain(m *testing.M) {
flag.Parse()
opt.Paths = flag.Args()

status := godog.RunWithOptions("godogs", func(s *godog.Suite) {
FeatureContext(s)
}, opt)

if st := m.Run(); st > status {
status = st
}
os.Exit(status)
}

func thereAreGodogs(available int) error {
Godogs = available
return nil
}

func iEat(num int) error {
err := assertExpectedAndActual(
assert.GreaterOrEqual, Godogs, num,
"You cannot eat %d godogs, there are %d available", num, Godogs,
)
if err != nil {
return err
}

Godogs -= num
return nil
}

func thereShouldBeRemaining(remaining int) error {
return assertExpectedAndActual(
assert.Equal, Godogs, remaining,
"Expected %d godogs to be remaining, but there is %d", remaining, Godogs,
)
}

func thereShouldBeNoneRemaining() error {
return assertActual(
assert.Empty, Godogs,
"Expected none godogs to be remaining, but there is %d", Godogs,
)
}

func FeatureContext(s *godog.Suite) {
s.Step(`^there are (\d+) godogs$`, thereAreGodogs)
s.Step(`^I eat (\d+)$`, iEat)
s.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
s.Step(`^there should be none remaining$`, thereShouldBeNoneRemaining)

s.BeforeScenario(func(*messages.Pickle) {
Godogs = 0 // clean the state before every scenario
})
}

// assertExpectedAndActual is a helper function to allow the step function to call
// assertion functions where you want to compare an expected and an actual value.
func assertExpectedAndActual(a expectedAndActualAssertion, expected, actual interface{}, msgAndArgs ...interface{}) error {
var t asserter
a(&t, expected, actual, msgAndArgs...)
return t.err
}

type expectedAndActualAssertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool

// assertActual is a helper function to allow the step function to call
// assertion functions where you want to compare an actual value to a
// predined state like nil, empty or true/false.
func assertActual(a actualAssertion, actual interface{}, msgAndArgs ...interface{}) error {
var t asserter
a(&t, actual, msgAndArgs...)
return t.err
}

type actualAssertion func(t assert.TestingT, actual interface{}, msgAndArgs ...interface{}) bool

// asserter is used to be able to retrieve the error reported by the called assertion
type asserter struct {
err error
}

// Errorf is used by the called assertion to report an error
func (a *asserter) Errorf(format string, args ...interface{}) {
a.err = fmt.Errorf(format, args...)
}

0 comments on commit 521a968

Please sign in to comment.