Documentation
¶
Overview ¶
Package httpdog provides HTTP-related step definitions for github.com/cucumber/godog.
Feature: Example Scenario: Successful GET Request Given "template-service" receives "GET" request "/template/hello" And "template-service" responds with status "OK" and body """ Hello, %s! """ When I request HTTP endpoint with method "GET" and URI "/?name=Jane" Then I should have response with status "OK" And I should have response with body """ Hello, Jane! """
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type External ¶
type External struct {
OnError func(err error)
Vars *shared.Vars
// contains filtered or unexported fields
}
External is a collection of step-driven HTTP servers to serve requests of application with mocked data.
func (*External) Add ¶
func (e *External) Add(service string, options ...func(mock *resttest.ServerMock)) string
Add starts a mocked server for a named service and returns url.
func (*External) RegisterSteps ¶
func (e *External) RegisterSteps(s *godog.ScenarioContext)
RegisterSteps adds steps to godog scenario context to serve outgoing requests with mocked data.
In simple case you can define expected URL and response.
Given "some-service" receives "GET" request "/get-something?foo=bar"
And "some-service" responds with status "OK" and body
"""
{"key":"value"}
"""
Or request with body.
And "another-service" receives "POST" request "/post-something" with body
"""
// Could be a JSON5 too.
{"foo":"bar"}
"""
Request with body from a file.
And "another-service" receives "POST" request "/post-something" with body from file """ _testdata/sample.json """
Request can expect to have a header.
And "some-service" request includes header "X-Foo: bar"
By default, each configured request is expected to be received 1 time. This can be changed to a different number.
And "some-service" request is received 1234 times
Or to be unlimited.
And "some-service" request is received several times
Response may have a header.
And "some-service" response includes header "X-Bar: foo"
Response must have status and body (body can be empty).
And "some-service" responds with status "OK" and body
"""
{"key":"value"}
"""
Response body can also be defined in file.
And "another-service" responds with status "200" and body from file """ _testdata/sample.json5 """
type Local ¶
Local is step-driven HTTP client for application local HTTP service.
func NewLocal ¶
NewLocal creates an instance of step-driven HTTP client.
Example ¶
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"github.com/bool64/httpdog"
"github.com/cucumber/godog"
)
func main() {
external := httpdog.External{}
templateService := external.Add("template-service")
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req, _ := http.NewRequest(http.MethodGet, templateService+"/template/hello", nil) // nolint // Handle errors.
resp, _ := http.DefaultTransport.RoundTrip(req) // nolint // Handle errors.
tpl, _ := ioutil.ReadAll(resp.Body) // nolint // Handle errors.
_, _ = w.Write([]byte(fmt.Sprintf(string(tpl), r.URL.Query().Get("name")))) // nolint // Handle errors.
})
srv := httptest.NewServer(h)
defer srv.Close()
local := httpdog.NewLocal(srv.URL)
suite := godog.TestSuite{
ScenarioInitializer: func(s *godog.ScenarioContext) {
local.RegisterSteps(s)
external.RegisterSteps(s)
},
Options: &godog.Options{
Format: "pretty",
Strict: true,
Paths: []string{"_testdata/Example.feature"},
Output: ioutil.Discard,
},
}
status := suite.Run()
if status != 0 {
fmt.Println("test failed")
} else {
fmt.Println("test passed")
}
}
Output: test passed
func (*Local) RegisterSteps ¶
func (l *Local) RegisterSteps(s *godog.ScenarioContext)
RegisterSteps adds HTTP server steps to godog scenario context.
Request Setup ¶
Request configuration needs at least HTTP method and URI.
When I request HTTP endpoint with method "GET" and URI "/get-something?foo=bar"
An additional header can be supplied. For multiple headers, call step multiple times.
And I request HTTP endpoint with header "X-Foo: bar"
Optionally request body can be configured. If body is a valid JSON5 payload, it will be converted to JSON before use. Otherwise, body is used as is.
And I request HTTP endpoint with body
"""
[
// JSON5 comments are allowed.
{"some":"json"}
]
"""
Request body can be provided from file.
And I request HTTP endpoint with body from file """ path/to/file.json5 """
If endpoint is capable of handling duplicated requests, you can check it for idempotency. This would send multiple requests simultaneously and check
- if all responses are similar or (all successful like GET),
- if responses can be grouped into exactly ONE response of a kind and OTHER responses of another kind (one successful, other failed like with POST).
Number of requests can be configured with `Local.ConcurrencyLevel`, default value is 10.
And I concurrently request idempotent HTTP endpoint
Response Expectations ¶
Response expectation has to be configured with at least one step about status, response body or other responses body (idempotency mode).
If response body is a valid JSON5 payload, it is converted to JSON before use.
JSON bodies are compared with https://github.com/swaggest/assertjson which allows ignoring differences when expected value is set to `"<ignore-diff>"`.
And I should have response with body
"""
[
{"some":"json","time":"<ignore-diff>"}
]
"""
Response body can be provided from file.
And I should have response with body from file """ path/to/file.json """
Status can be defined with either phrase or numeric code. Also you can set response header expectations.
Then I should have response with status "OK" And I should have response with header "Content-Type: application/json" And I should have response with header "X-Header: abc"
In an idempotent mode you can set expectations for statuses of other responses.
Then I should have response with status "204" And I should have other responses with status "Not Found" And I should have other responses with header "Content-Type: application/json"
And for bodies of other responses.
And I should have other responses with body
"""
{"status":"failed"}
"""
Which can be defined as files.
And I should have other responses with body from file """ path/to/file.json """