### Install Godog CLI Source: https://github.com/cucumber/godog/blob/main/README.md Install the Godog CLI using `go install`. Specify a version using `@latest` or a specific tag like `@v0.12.0`. ```sh go install github.com/cucumber/godog/cmd/godog@latest ``` -------------------------------- ### Install Godog CLI with Older Go Versions Source: https://github.com/cucumber/godog/blob/main/README.md For Go versions prior to 1.17, use `go get` to install the Godog CLI. If running within `$GOPATH`, set `GO111MODULE=on`. ```sh go get github.com/cucumber/godog/cmd/godog@v0.12.0 ``` ```sh GO111MODULE=on go get github.com/cucumber/godog/cmd/godog@v0.12.0 ``` -------------------------------- ### Main Program for Godog Example Source: https://github.com/cucumber/godog/blob/main/README.md A simple Go program with a global variable for tracking the number of godogs. ```go package main // Godogs available to eat var Godogs int func main() { /* usual main func */ } ``` -------------------------------- ### Update Go Module Dependencies Source: https://github.com/cucumber/godog/blob/main/CONTRIBUTING.md Run this command after changing project dependencies to ensure the go.mod file is up-to-date. This is typically sufficient for updating the examples module as well. ```bash go mod tidy ``` -------------------------------- ### Run Godog with TestMain and Manual Options Source: https://github.com/cucumber/godog/blob/main/README.md Configure Godog options manually within `TestMain` when not binding flags. This example shows how to set the format, paths, and randomize scenario execution order. ```go func TestMain(m *testing.M) { opts := godog.Options{ Format: "progress", Paths: []string{"features"}, Randomize: time.Now().UTC().UnixNano(), // randomize scenario execution order } status := godog.TestSuite{ Name: "godogs", TestSuiteInitializer: InitializeTestSuite, ScenarioInitializer: InitializeScenario, Options: &opts, }.Run() // Optional: Run `testing` package's logic besides godog. if st := m.Run(); st > status { status = st } os.Exit(status) } ``` -------------------------------- ### Gherkin Feature File Example Source: https://github.com/cucumber/godog/blob/main/README.md Defines a feature for eating godogs, including a scenario with specific steps. ```gherkin 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 5 Then there should be 7 remaining ``` -------------------------------- ### Run Godog with TestMain and Flag Binding Source: https://github.com/cucumber/godog/blob/main/README.md Integrate Godog with `TestMain` and bind Godog flags with a custom prefix to avoid collisions. This example uses `godog.BindFlags` for older versions and `godog.BindCommandLineFlags` for v0.11.0 and later. ```go package main import ( os "testing" "github.com/cucumber/godog" "github.com/cucumber/godog/colors" "github.com/spf13/pflag" // godog v0.11.0 and later ) var opts = godog.Options{ Output: colors.Colored(os.Stdout), Format: "progress", // can define default values } func init() { godog.BindFlags("godog.", pflag.CommandLine, &opts) // godog v0.10.0 and earlier godog.BindCommandLineFlags("godog.", &opts) // godog v0.11.0 and later } func TestMain(m *testing.M) { pflag.Parse() opts.Paths = pflag.Args() status := godog.TestSuite{ Name: "godogs", TestSuiteInitializer: InitializeTestSuite, ScenarioInitializer: InitializeScenario, Options: &opts, }.Run() // Optional: Run `testing` package's logic besides godog. if st := m.Run(); st > status { status = st } os.Exit(status) } ``` -------------------------------- ### API Server Implementation Source: https://github.com/cucumber/godog/blob/main/_examples/api/README.md Implements a simple REST API server with a GET /version endpoint. It uses Go's standard http package and godog for version information. ```go // file: api.go // Example - demonstrates REST API server implementation tests. package main import ( "encoding/json" "net/http" "github.com/cucumber/godog" ) func getVersion(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { fail(w, "Method not allowed", http.StatusMethodNotAllowed) return } data := struct { Version string `json:"version"` }{Version: godog.Version} ok(w, data) } // fail writes a json response with error msg and status header func fail(w http.ResponseWriter, msg string, status int) { w.WriteHeader(status) data := struct { Error string `json:"error"` }{Error: msg} resp, _ := json.Marshal(data) w.Header().Set("Content-Type", "application/json") w.Write(resp) } // ok writes data to response with 200 status func ok(w http.ResponseWriter, data interface{}) { resp, err := json.Marshal(data) if err != nil { fail(w, "Oops something evil has happened", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(resp) } func main() { http.HandleFunc("/version", getVersion) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Run Godog with testing.T Subtests Source: https://github.com/cucumber/godog/blob/main/README.md Use `testing.T` subtests to run Godog scenarios. This method does not require the Godog command to be installed. The `TestingT` option is set to the current `testing.T` instance. ```go package main_test import ( testing "github.com/cucumber/godog" ) func TestFeatures(t *testing.T) { suite := godog.TestSuite{ ScenarioInitializer: func(s *godog.ScenarioContext) { // Add step definitions here. }, Options: &godog.Options{ Format: "pretty", Paths: []string{"features"}, TestingT: t, // Testing instance that will run subtests. }, } if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run feature tests") } } ``` -------------------------------- ### API Step Definitions for Godog Source: https://github.com/cucumber/godog/blob/main/_examples/api/README.md Defines the step implementations for testing an API. It includes setup for HTTP requests and response assertions, and integrates with the godog testing framework. ```go // file: api_test.go package main import ( "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "reflect" "testing" "github.com/cucumber/godog" ) type apiFeature struct { resp *httptest.ResponseRecorder } func (a *apiFeature) resetResponse(*godog.Scenario) { a.resp = httptest.NewRecorder() } func (a *apiFeature) iSendrequestTo(method, endpoint string) (err error) { req, err := http.NewRequest(method, endpoint, nil) if err != nil { return } // handle panic defer func() { switch t := recover().(type) { case string: err = fmt.Errorf(t) case error: err = t } }() switch endpoint { case "/version": getVersion(a.resp, req) default: err = fmt.Errorf("unknown endpoint: %s", endpoint) } return } func (a *apiFeature) theResponseCodeShouldBe(code int) error { if code != a.resp.Code { return fmt.Errorf("expected response code to be: %d, but actual is: %d", code, a.resp.Code) } return nil } func (a *apiFeature) theResponseShouldMatchJSON(body *godog.DocString) (err error) { var expected, actual interface{} // re-encode expected response if err = json.Unmarshal([]byte(body.Content), &expected); err != nil { return } // re-encode actual response too if err = json.Unmarshal(a.resp.Body.Bytes(), &actual); err != nil { return } // the matching may be adapted per different requirements. if !reflect.DeepEqual(expected, actual) { return fmt.Errorf("expected JSON does not match actual, %v vs. %v", expected, actual) } return nil } func TestFeatures(t *testing.T) { suite := godog.TestSuite{ ScenarioInitializer: InitializeScenario, Options: &godog.Options{ Format: "pretty", Paths: []string{"features"}, TestingT: t, // Testing instance that will run subtests. }, } if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run feature tests") } } func InitializeScenario(ctx *godog.ScenarioContext) { api := &apiFeature{} ctx.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) { api.resetResponse(sc) return ctx, nil }) ctx.Step(`^I send "(GET|POST|PUT|DELETE)" request to "([^\"]*)"$`, api.iSendrequestTo) ctx.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) ctx.Step(`^the response should match json:$`, api.theResponseShouldMatchJSON) } ``` -------------------------------- ### Alias Godog CLI Commands Source: https://github.com/cucumber/godog/blob/main/README.md Create aliases for common or project-specific Godog CLI commands to streamline workflow. This example creates an alias for tests tagged with `@wip`. ```sh alias godog-wip="godog --format=progress --tags=@wip" ``` -------------------------------- ### Compile and Run Test Binary Source: https://github.com/cucumber/godog/blob/main/README.md Steps to compile the test binary and run it from a different directory. This demonstrates the independent execution enabled by `go:embed`. ```sh > go test -c ./test/integration/integration_test.go > mv integration.test /some/random/dir > cd /some/random/dir > ./integration.test ``` -------------------------------- ### Run Project Tests Source: https://github.com/cucumber/godog/blob/main/CONTRIBUTING.md Execute this command to ensure your development environment is set up correctly and all tests pass. ```bash make test ``` -------------------------------- ### Godog Step Definitions (Standard) Source: https://github.com/cucumber/godog/blob/main/README.md Implements step definitions for the godog feature file using the standard InitializeScenario function. ```go package main import "github.com/cucumber/godog" func iEat(arg1 int) error { return godog.ErrPending } func thereAreGodogs(arg1 int) error { return godog.ErrPending } func thereShouldBeRemaining(arg1 int) error { return godog.ErrPending } func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Step(`^there are (\d+) godogs$`, thereAreGodogs) ctx.Step(`^I eat (\d+)$`, iEat) ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) } ``` -------------------------------- ### Godog Step Definitions (Keyword Specific) Source: https://github.com/cucumber/godog/blob/main/README.md Implements step definitions for the godog feature file, specifying Given, When, and Then keywords. ```go func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Given(`^there are (\d+) godogs$`, thereAreGodogs) ctx.When(`^I eat (\d+)$`, iEat) ctx.Then(`^there should be (\d+) remaining$`, thereShouldBeRemaining) } ``` -------------------------------- ### Run Godog with TestMain and Dynamic Format Source: https://github.com/cucumber/godog/blob/main/README.md Dynamically set the Godog format based on `go test` flags, such as `-test.v`. This allows switching to 'pretty' format when verbose mode is enabled. ```go func TestMain(m *testing.M) { format := "progress" for _, arg := range os.Args[1:] { if arg == "-test.v=true" { // go test transforms -v option format = "pretty" break } } opts := godog.Options{ Format: format, Paths: []string{"features"}, } status := godog.TestSuite{ Name: "godogs", TestSuiteInitializer: InitializeTestSuite, ScenarioInitializer: InitializeScenario, Options: &opts, }.Run() // Optional: Run `testing` package's logic besides godog. if st := m.Run(); st > status { status = st } os.Exit(status) } ``` -------------------------------- ### Go Step Definitions with Context Source: https://github.com/cucumber/godog/blob/main/README.md Implements step definitions for a 'godogs' feature using context.Context to store and retrieve the number of available godogs. This pattern is useful for managing state across steps within a scenario. ```go package main import ( "context" "errors" "fmt" "testing" "github.com/cucumber/godog" ) // godogsCtxKey is the key used to store the available godogs in the context.Context. type godogsCtxKey struct{} func thereAreGodogs(ctx context.Context, available int) (context.Context, error) { return context.WithValue(ctx, godogsCtxKey{}, available), nil } func iEat(ctx context.Context, num int) (context.Context, error) { available, ok := ctx.Value(godogsCtxKey{}).(int) if !ok { return ctx, errors.New("there are no godogs available") } if available < num { return ctx, fmt.Errorf("you cannot eat %d godogs, there are %d available", num, available) } available -= num return context.WithValue(ctx, godogsCtxKey{}, available), nil } func thereShouldBeRemaining(ctx context.Context, remaining int) error { available, ok := ctx.Value(godogsCtxKey{}).(int) if !ok { return errors.New("there are no godogs available") } if available != remaining { return fmt.Errorf("expected %d godogs to be remaining, but there is %d", remaining, available) } return nil } func TestFeatures(t *testing.T) { suite := godog.TestSuite{ ScenarioInitializer: InitializeScenario, Options: &godog.Options{ Format: "pretty", Paths: []string{"features"}, TestingT: t, // Testing instance that will run subtests. }, } if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run feature tests") } } func InitializeScenario(sc *godog.ScenarioContext) { sc.Step(`^there are (\d+) godogs$`, thereAreGodogs) sc.Step(`^I eat (\d+)$`, iEat) sc.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) } ``` -------------------------------- ### Go Step Definitions for API Testing Source: https://github.com/cucumber/godog/blob/main/_examples/api/README.md Implements the step definitions for the Gherkin feature file. This code should be placed in `api_test.go` and requires the `godog` package. It sets up the test suite and initializes scenarios. ```go // file: api_test.go package main import ( "github.com/cucumber/godog" ) type apiFeature struct { } func (a *apiFeature) iSendrequestTo(method, endpoint string) error { return godog.ErrPending } func (a *apiFeature) theResponseCodeShouldBe(code int) error { return godog.ErrPending } func (a *apiFeature) theResponseShouldMatchJSON(body *godog.DocString) error { return godog.ErrPending } func TestFeatures(t *testing.T) { suite := godog.TestSuite{ ScenarioInitializer: InitializeScenario, Options: &godog.Options{ Format: "pretty", Paths: []string{"features"}, TestingT: t, // Testing instance that will run subtests. }, } if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run feature tests") } } func InitializeScenario(s *godog.ScenarioContext) { api := &apiFeature{} s.Step(`^I send "([^ "]*)" request to "([^ "]*)"$`, api.iSendrequestTo) s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) s.Step(`^the response should match json:$`, api.theResponseShouldMatchJSON) } ``` -------------------------------- ### Use Assertion Packages with Godog Source: https://github.com/cucumber/godog/blob/main/README.md Integrate assertion packages like testify with Godog by using `godog.T(ctx)` to access the testing instance within your step definitions. ```go func thereShouldBeRemaining(ctx context.Context, remaining int) error { assert.Equal( godog.T(ctx), Godogs, remaining, "Expected %d godogs to be remaining, but there is %d", remaining, Godogs, ) return nil } ``` -------------------------------- ### Run Emoji Formatter Source: https://github.com/cucumber/godog/blob/main/_examples/custom-formatter/README.md Use the '-f emoji' flag to enable the emoji progress formatter when running godog tests. ```bash godog -f emoji ``` -------------------------------- ### Embed Features with go:embed Source: https://github.com/cucumber/godog/blob/main/README.md Embed feature files into the test binary using `go:embed`. This allows the test binary to be compiled and run independently of the feature files. ```go //go:embed features/* var features embed.FS var opts = godog.Options{ Paths: []string{"features"}, FS: features, } ``` -------------------------------- ### Gherkin Feature Definition for API Source: https://github.com/cucumber/godog/blob/main/_examples/api/README.md Defines API scenarios in Gherkin format, including success and error cases for a version endpoint. This file should be saved as `features/version.feature`. ```gherkin # file: version.feature Feature: get version In order to know godog version As an API user I need to be able to request version Scenario: does not allow POST method When I send "POST" request to "/version" Then the response code should be 405 And the response should match json: """ { "error": "Method not allowed" } """ Scenario: should get version number When I send "GET" request to "/version" Then the response code should be 200 And the response should match json: """ { "version": "v0.0.0-dev" } """ ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.