Documentation ¶
Overview ¶
Package httpsteps 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 ¶
- Constants
- func DefaultExposeHTTPDetails(ctx context.Context, d httpmock.HTTPValue) (context.Context, error)
- func LoadBody(body []byte, vars *shared.Vars) ([]byte, error)deprecated
- func LoadBodyFromFile(filePath string, vars *shared.Vars) ([]byte, error)deprecated
- type ExternalServer
- type HTTPValue
- type LocalClient
Examples ¶
Constants ¶
const (
// Default is the name of default service.
Default = "default"
)
Variables ¶
This section is empty.
Functions ¶
func DefaultExposeHTTPDetails ¶ added in v0.2.15
DefaultExposeHTTPDetails instruments context with godog.Attachment items of HTTP transaction.
Types ¶
type ExternalServer ¶
type ExternalServer struct { // Deprecated: use VS.JSONComparer.Vars to seed initial values if necessary. Vars *shared.Vars VS *vars.Steps // contains filtered or unexported fields }
ExternalServer is a collection of step-driven HTTP servers to serve requests of application with mocked data.
Please use NewExternalServer() to create an instance.
func NewExternalServer ¶ added in v0.2.0
func NewExternalServer() *ExternalServer
NewExternalServer creates an ExternalServer.
func (*ExternalServer) Add ¶
func (e *ExternalServer) Add(service string, options ...func(mock *httpmock.Server)) string
Add starts a mocked server for a named service and returns url.
func (*ExternalServer) GetMock ¶
func (e *ExternalServer) GetMock(service string) *httpmock.Server
GetMock exposes mock of external service for configuration.
func (*ExternalServer) RegisterSteps ¶
func (e *ExternalServer) 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
By default, requests are expected in same sequential order as they are defined. If there is no stable order you can have an async expectation. Async requests are expected in any order.
And "some-service" request is async
Response may have a header.
And "some-service" response includes header "X-Bar: foo"
Response must have a status.
And "some-service" responds with status "OK"
Response may also have a body.
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 LocalClient ¶
type LocalClient struct { // Deprecated: use VS.JSONComparer.Vars. Vars *shared.Vars VS *vars.Steps RetryBackOff func(ctx context.Context, maxElapsedTime time.Duration) (context.Context, httpmock.RetryBackOff) // ExposeHTTPDetails enables godog.Attachment for request and response data. // Has DefaultExposeHTTPDetails by default. ExposeHTTPDetails func(ctx context.Context, d httpmock.HTTPValue) (context.Context, error) // contains filtered or unexported fields }
LocalClient is step-driven HTTP service for application local HTTP service.
func NewLocalClient ¶
func NewLocalClient(defaultBaseURL string, options ...func(*httpmock.Client)) *LocalClient
NewLocalClient creates an instance of step-driven HTTP service.
Example ¶
package main import ( "fmt" "io" "net/http" "net/http/httptest" "github.com/cucumber/godog" "github.com/godogx/httpsteps" ) func main() { external := httpsteps.NewExternalServer() templateService := external.Add("template-service") h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { req, _ := http.NewRequest(http.MethodGet, templateService+"/template/hello", nil) resp, _ := http.DefaultTransport.RoundTrip(req) tpl, _ := io.ReadAll(resp.Body) _ = resp.Body.Close() _, _ = w.Write([]byte(fmt.Sprintf(string(tpl), r.URL.Query().Get("name")))) }) srv := httptest.NewServer(h) defer srv.Close() local := httpsteps.NewLocalClient(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: io.Discard, }, } if suite.Run() != 0 { fmt.Println("test failed") } else { fmt.Println("test passed") } }
Output: test passed
func (*LocalClient) AddService ¶
func (l *LocalClient) AddService(name, baseURL string)
AddService registers a URL for named service.
func (*LocalClient) RegisterSteps ¶
func (l *LocalClient) 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"
Configuration can be bound to a specific named service. This service must be registered before. service name should be added before `HTTP endpoint`.
And I request "some-service" HTTP endpoint with header "X-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"
An additional cookie can be supplied. For multiple cookie, call step multiple times.
And I request HTTP endpoint with cookie "name: value"
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 `LocalClient.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 """
More information at https://github.com/godogx/httpsteps/#local-client.
func (*LocalClient) Service ¶
func (l *LocalClient) Service(ctx context.Context, service string) (*httpmock.Client, context.Context, error)
Service returns named service client or fails for undefined service.
func (*LocalClient) SetBaseURL ¶ added in v0.2.3
func (l *LocalClient) SetBaseURL(baseURL string, service string) error
SetBaseURL sets the base URL for the client.