mockhttp

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2022 License: Apache-2.0 Imports: 15 Imported by: 0

README

go-mockhttp

Package for mocking HTTP servers and clients.

Main Features

It provides the following main features:

  1. Mock using real HTTP server with simply defined endpoints and expected behavior
  2. Verify expectations
  3. Simulate server faults, such as response delays
  4. Simulate transport errors, such as connection failures

Usage

A common use case is to start a mock HTTP server in your test, define endpoints, call your code which is expected to send requests to an HTTP server, and verify the expectations.

// Start a mock http server with a single endpoint which matches a request and returns a response
server := mockhttp.StartServer(mockhttp.WithEndpoints(
	mockhttp.NewServerEndpoint().
		When(mockhttp.Request().GET("/foo")). // When received request matches: GET /foo (with any headers)
		Respond(mockhttp.Response())))        // Respond with default response (status 200 OK, empty body, no headers)
// Make sure to close it
defer server.Close()

// Issue a request to the server (this is usually done by the code under test...)
res, err := http.Get(server.BaseUrl() + "/foo")
// check the error

// Verify that the server got the request as expected
if err := server.Verify(mockhttp.Request().GET("/foo"), mockhttp.Times(1)); err != nil {
	t.Errorf("failed expectations: %v", err)
}

The above is a very basic and simple use case. For mode details and usage options, see the package's documentation.

Documentation

Overview

Package for mocking HTTP servers and clients.

See the examples to get a starting point. For more details, refer to the documentation of each function / type.

Example (Client)

A common use case for the mock http client is to mock transport errors.

// Create a new mock http client with a single endpoint
// The endpoint matches any request ("When" is not specified), and always returns an error
client := mockhttp.NewClient(mockhttp.NewClientEndpoint().ReturnError(fmt.Errorf("dummy error")))

// Provide the client to what ever you test, it will get an error when using the client to send a request
// In this example we simply use the HTTP client directly...
_, err := client.HttpClient().Get("http://myhost/foo/bar")

if err == nil || err.Error() != "Get http://myhost/foo/bar: dummy error" {
	// Fail the test: t.Errorf("error is not as expected: %v", err)
}
Output:

Example (Server)

Start a mock http server as a test double for other external servers. The code under test keeps sending real requests, but instead of sending to the real target, it should send to the mock server. The mock server receives requests and responds as configured.

// Start a mock http server with a single endpoint
server := mockhttp.StartServer(mockhttp.WithEndpoints(
	mockhttp.NewServerEndpoint().
		When(mockhttp.Request().GET("/foo")). // When receiving a GET request to path "/foo"
		Respond(mockhttp.Response())))        // Respond with a default response (status OK)
// Make sure to close it
defer server.Close()

// Issue a request to the server (this is usually done by the code under test...)
_, _ = http.Get(server.BaseUrl() + "/foo")
// Check the response and the error

// Verify that the server got the request as expected
if err := server.Verify(mockhttp.Request().GET("/foo"), mockhttp.Times(1)); err != nil {
	// Fail the test: t.Errorf("failed expectations: %v", err)
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AtLeast

func AtLeast(times int) verifyOpt

Verify functional option to set, a request is expected at least number of given times

func AtMost

func AtMost(times int) verifyOpt

Verify functional option to set, a request is expected at most number of given times

func MustReadAll

func MustReadAll(t *testing.T, r io.Reader) []byte

Helper utility function to read all bytes of a given reader. Will fail the test in case of an error while reading.

func Never

func Never() verifyOpt

Verify functional option to set, a request is never expected

func NewClientEndpoint

func NewClientEndpoint() *clientEndpoint

Create a new client endpoint, to be used for configuring a mock http client

func NewServerEndpoint

func NewServerEndpoint() *serverEndpoint

Create a new server endpoint, to be used for configuring a mock http server

func Once

func Once() verifyOpt

Verify functional option to set, a request is expected exactly once

func Request

func Request() *requestMatcher

Create a new request matcher. By default it matches everything. Use configuration methods to narrow down what matches and what not. All limitations are handled with AND.

For example:

Request().
	Method("DELETE").
	Path("/foo").
	Header("Content-Type", "application/json")

func Response

func Response() *response

Create a new response definition. To be used e.g. with the ServerEndpoint's Respond builder function.

Defaults:

  • Status code: OK 200
  • Empty body
  • No headers
  • No delay

func Times

func Times(expected int) verifyOpt

Verify functional option to set how many times a request is expected

func WithServers

func WithServers(serverSpecs ServerSpecs, test TestWithMockServers)

Helper function to run a test with multiple mock http servers.

Providing mock http server specifications, this function will make sure to start all servers, run the test, and close all servers after the test. This way the test function can focus on the test itself instead of managing the mock http servers. The test function receives a map of servers (already configured and running), matching the map of server specifications.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Mock http client

func NewClient

func NewClient(endpoints ...ClientEndpoint) *Client

Create a new mock http client with a list of client endpoints it should handle

A common use case for this mock http client is to mock transport errors. For example:

  // create a new mock http client which returns a given error
  client := NewClient(NewClientEndpoint().ReturnError(fmt.Errorf("dummy error")))

  //provide the client to what ever you test, it will get an error when using the client to send a request
  result, err := mylib.CallSomethingUsingClient(client.HttpClient())

	 // assert the above call behaves as expected, e.g. returns an error

func (*Client) AcceptedRequests

func (c *Client) AcceptedRequests() []recordedRequest

Get all requests which this client received and were handled by one of the defined endpoints

func (*Client) ClearHistory

func (c *Client) ClearHistory()

Clean all the request history recorded by this client

func (*Client) HttpClient

func (c *Client) HttpClient() *http.Client

Get the actual http client, to be used by tests

func (*Client) UnmatchedRequests

func (c *Client) UnmatchedRequests() []recordedRequest

Get all requests which this client received but did not match any of the defined endpoints

type ClientEndpoint

type ClientEndpoint interface {
	http.RoundTripper
	Matches(request *http.Request) bool
}

Client endpoint interface, used by a mock http client for handling outgoing requests

type RoundTripFunc

type RoundTripFunc func(*http.Request) (*http.Response, error)

Function for handling a request

type Server

type Server struct {
	Port int
	// contains filtered or unexported fields
}

Mock http server

func StartServer

func StartServer(opts ...ServerOpt) *Server

Start a new mock http server

The server is configured using the provided functional options. The defaults are:

  • Name: "anonymous"
  • TLS disabled
  • No handled endpoints - all requests return 404

Make sure to close the server when done. A common practice is to use:

server := StartServer() // Configure as needed
defer server.Close()

func (*Server) AcceptedRequests

func (mockSvr *Server) AcceptedRequests() []recordedRequest

Get all requests which got to this server and were handled by one of the defined endpoints

func (*Server) AddEndpoint

func (mockSvr *Server) AddEndpoint(endpoint ServerEndpoint)

Add an endpoint to this server

func (*Server) BaseUrl

func (mockSvr *Server) BaseUrl() string

The base URL of this server

The URL is constructed based on whether TLS is enabled ("http" or "https") and on the port the server started with. An example base URL would be:

http://localhost:54756

func (*Server) BuildUrl

func (mockSvr *Server) BuildUrl(path string) string

Build a URL based on the server's base URL and the given path

For example:

url := server.BuildUrl("/path/to/something")
// url == "http://localhost:54756/path/to/something"

func (*Server) Clear

func (mockSvr *Server) Clear()

Clear request history and remove all endpoints defined for this server

Helpful when reusing the same mock http server for multiple tests, to make sure a clean start

func (*Server) ClearHistory

func (mockSvr *Server) ClearHistory()

Clean all the request history recorded by this server

func (*Server) Close

func (mockSvr *Server) Close()

Close (shutdown) the server

func (*Server) String

func (mockSvr *Server) String() string

func (*Server) UnmatchedRequests

func (mockSvr *Server) UnmatchedRequests() []recordedRequest

Get all requests which got to this server but did not match any of the defined endpoints

func (*Server) Verify

func (mockSvr *Server) Verify(matcher *requestMatcher, opts ...verifyOpt) error

Verify requests received by this server. Requires a request matcher to specify which requests to check and optionally verify options (e.g. how many times, etc.). If it does not match the expectation, an error is returned, otherwise returns nil.

For example:

// verify that the server got a GET request with path "/foo" exactly twice
err := server.Verify(Request().GET("/foo"), Times(2)
if err != nil {
	t.Errorf("%v", err)
}

func (*Server) WaitFor

func (mockSvr *Server) WaitFor(ctx context.Context, matcher *requestMatcher) error

Wait for a request (matching the given matcher) to be received by the server, no matter if an matching endpoint is defined. The provided context can be used e.g. for setting a timeout. Returns an error e.g. when waiting has timed out.

For example:

// Wait for any request with timeout of 5 seconds
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer cancel()
err := server.WaitFor(ctx, Request())

type ServerEndpoint

type ServerEndpoint interface {
	http.Handler
	Matches(request *http.Request) bool
}

Server endpoint interface, used by a mock http server for handling incoming requests

type ServerOpt

type ServerOpt func(*Server)

Functional option for configuring a mock http server

func WithEndpoints

func WithEndpoints(endpoints ...ServerEndpoint) ServerOpt

Set the endpoints the server shall handle

func WithName

func WithName(name string) ServerOpt

Set the name of the mock http server.

Used mainly for logging, has no real functional purpose. Set to "anonymous" if not explicitly set.

func WithTls

func WithTls(config *tls.Config) ServerOpt

Set TLS configuration, to start the mock http server with TLS enabled.

A server is started without TLS by default if not explicitly set.

type ServerSpecs

type ServerSpecs map[string][]ServerEndpoint

Map of server specifications, used for specifying multiple servers to start

type Servers

type Servers map[string]*Server

Map of mock http servers

type TestWithMockServers

type TestWithMockServers func(servers Servers)

Test function which receives a collection of running mock http servers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL