httpmock

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2021 License: MIT Imports: 16 Imported by: 0

README

HTTP Mock for Golang

Build Status codecov

httpmock is a mock library implementing httptest.Server to support HTTP behavioral tests.

Install

go get github.com/nhatthm/httpmock

Examples

func Test_Simple(t *testing.T) {
	mockServer := httpmock.New(func(s *httpmock.Server) {
		s.Expect(http.MethodGet, "/").
			Return("hello world!")
	})

	s := mockServer(t)

	code, _, body, _ := request(t, s.URL(), http.MethodGet, "/", nil, nil, 0)

	expectedCode := http.StatusOK
	expectedBody := []byte(`hello world!`)

	assert.Equal(t, expectedCode, code)
	assert.Equal(t, expectedBody, body)
  
	// Success
}

func Test_CustomResponse(t *testing.T) {
	mockServer := httpmock.New(func(s *httpmock.Server) {
		s.Expect(http.MethodPost, "/create").
			WithHeader("Authorization", "Bearer token").
			WithBody(`{"name":"John Doe"}`).
			After(time.Second).
			ReturnCode(http.StatusCreated)
			ReturnJSON(map[string]interface{}{
				"id":   1,
				"name": "John Doe",
			})
	})

	s := mockServer(t)

	requestHeader := map[string]string{"Authorization": "Bearer token"}
	requestBody := []byte(`{"name":"John Doe"}`)
	code, _, body, _ := request(t, s.URL(), http.MethodPost, "/create", requestHeader, requestBody, time.Second)

	expectedCode := http.StatusCreated
	expectedBody := []byte(`{"id":1,"name":"John Doe"}`)

	assert.Equal(t, expectedCode, code)
	assert.Equal(t, expectedBody, body)

	// Success
}

func Test_ExpectationsWereNotMet(t *testing.T) {
	mockServer := httpmock.New(func(s *httpmock.Server) {
		s.Expect(http.MethodGet, "/").
			Return("hello world!")

		s.Expect(http.MethodPost, "/create").
			WithHeader("Authorization", "Bearer token").
			WithBody(`{"name":"John Doe"}`).
			After(time.Second).
			ReturnJSON(map[string]interface{}{
				"id":   1,
				"name": "John Doe",
			})
	})

	s := mockServer(t)

	code, _, body, _ := request(t, s.URL(), http.MethodGet, "/", nil, nil, 0)

	expectedCode := http.StatusOK
	expectedBody := []byte(`hello world!`)

	assert.Equal(t, expectedCode, code)
	assert.Equal(t, expectedBody, body)
  
	// The test fails with
	// Error:      	Received unexpected error:
	//             	there are remaining expectations that were not met:
	//             	- POST /create
	//             	    with header:
	//             	        Authorization: Bearer token
	//             	    with body:
	//             	        {"name":"John Doe"}
}

func request(
	t *testing.T,
	baseURL string,
	method, uri string,
	headers map[string]string,
	body []byte,
	waitTime time.Duration,
) (int, map[string]string, []byte, time.Duration) {
	t.Helper()

	var reqBody io.Reader

	if body != nil {
		reqBody = strings.NewReader(string(body))
	}

	req, err := http.NewRequest(method, baseURL+uri, reqBody)
	require.NoError(t, err, "could not create a new request")

	for header, value := range headers {
		req.Header.Set(header, value)
	}

	timeout := waitTime + time.Second
	client := http.Client{Timeout: timeout}

	start := time.Now()
	resp, err := client.Do(req)
	elapsed := time.Since(start)

	require.NoError(t, err, "could not make a request to mocked server")

	respCode := resp.StatusCode
	respHeaders := map[string]string(nil)

	if len(resp.Header) > 0 {
		respHeaders = map[string]string{}

		for header := range resp.Header {
			respHeaders[header] = resp.Header.Get(header)
		}
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	require.NoError(t, err, "could not read response body")

	err = resp.Body.Close()
	require.NoError(t, err, "could not close response body")

	return respCode, respHeaders, respBody, elapsed
}

Documentation

Overview

Package httpmock provides functionalities for mocking http server.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnsupportedDataType = errors.New("unsupported data type")

ErrUnsupportedDataType represents that the data type is not supported.

Functions

func GetBody

func GetBody(r *http.Request) ([]byte, error)

GetBody returns request body and lets it re-readable.

Types

type BodyMatcher

type BodyMatcher func(expected, body []byte) bool

BodyMatcher matches a body with an expectation.

func ExactBodyMatcher

func ExactBodyMatcher() BodyMatcher

ExactBodyMatcher matches a body by checking if it is equal to the expectation.

type Header map[string]string

Header is a list of HTTP headers.

type HeaderMatcher

type HeaderMatcher func(expected, header string) bool

HeaderMatcher matches header with an expectation.

func ExactHeaderMatcher

func ExactHeaderMatcher() HeaderMatcher

ExactHeaderMatcher matches a header by checking if it is equal to the expectation.

type Mocker

type Mocker func(t TestingT) *Server

Mocker is a function that applies expectations to the mocked server.

func New

func New(mocks ...func(s *Server)) Mocker

New creates a mocker server with expectations and assures that ExpectationsWereMet() is called.

type Request

type Request struct {

	// Method is the expected HTTP Method of the given request.
	Method string
	// RequestURI is the expected HTTP Request URI of the given request.
	// The uri does not need to be exactly same but satisfies the URIMatcher.
	RequestURI string
	// RequestHeader is a list of expected headers of the given request.
	RequestHeader Header
	// RequestBody is the expected body of the given request.
	RequestBody []byte

	// StatusCode is the response code when the request is handled.
	StatusCode int
	// ResponseHeader is a list of response headers to be sent to client when the request is handled.
	ResponseHeader Header
	// Do handles the request and returns a result or an error.
	Do RequestHandler

	// The number of times to return the return arguments when setting
	// expectations. 0 means to always return the value.
	Repeatability int
	// contains filtered or unexported fields
}

Request is an expectation.

func (*Request) After

func (r *Request) After(d time.Duration) *Request

After sets how long to block until the call returns

Server.Expect(http.MethodGet, "/path").
	After(time.Second).
	Return("hello world!")

func (*Request) Once

func (r *Request) Once() *Request

Once indicates that that the mock should only return the value once.

Server.Expect(http.MethodGet, "/path").
	Return("hello world!").
	Once()

func (*Request) RequestHandler

func (r *Request) RequestHandler(handler RequestHandler) *Request

RequestHandler sets the handler to handle a given request.

   Server.Expect(http.MethodGet, "/path").
		RequestHandler(func(_ *http.Request) ([]byte, error) {
			return []byte("hello world!"), nil
		})

func (*Request) Return

func (r *Request) Return(v interface{}) *Request

Return sets the result to return to client.

Server.Expect(http.MethodGet, "/path").
	Return("hello world!")

func (*Request) ReturnCode

func (r *Request) ReturnCode(code int) *Request

ReturnCode sets the response code.

Server.Expect(http.MethodGet, "/path").
	ReturnCode(http.StatusBadRequest)

func (*Request) ReturnFile added in v0.1.1

func (r *Request) ReturnFile(filePath string) *Request

ReturnFile reads the file using ioutil.ReadFile and uses it as the result to return to client.

Server.Expect(http.MethodGet, "/path").
	ReturnFile("resources/fixtures/response.txt")

nolint:unparam

func (*Request) ReturnHeader

func (r *Request) ReturnHeader(header, value string) *Request

ReturnHeader sets a response header.

Server.Expect(http.MethodGet, "/path").
	ReturnHeader("foo", "bar")

func (*Request) ReturnHeaders

func (r *Request) ReturnHeaders(headers Header) *Request

ReturnHeaders sets a list of response headers.

Server.Expect(http.MethodGet, "/path").
	ReturnHeaders(httpmock.Header{"foo": "bar"})

func (*Request) ReturnJSON

func (r *Request) ReturnJSON(body interface{}) *Request

ReturnJSON marshals the object using json.Marshal and uses it as the result to return to client.

Server.Expect(http.MethodGet, "/path").
	ReturnJSON(map[string]string{"foo": "bar"})

func (*Request) Times

func (r *Request) Times(i int) *Request

Times indicates that that the mock should only return the indicated number of times.

Server.Expect(http.MethodGet, "/path").
	Return("hello world!").
	Times(5)

func (*Request) Twice

func (r *Request) Twice() *Request

Twice indicates that that the mock should only return the value twice.

Server.Expect(http.MethodGet, "/path").
	Return("hello world!").
	Twice()

func (*Request) WaitUntil

func (r *Request) WaitUntil(w <-chan time.Time) *Request

WaitUntil sets the channel that will block the mock's return until its closed or a message is received.

Server.Expect(http.MethodGet, "/path").
	WaitUntil(time.After(time.Second)).
	Return("hello world!")

func (*Request) WithBody

func (r *Request) WithBody(body interface{}) *Request

WithBody sets the expected body of the given request.

Server.Expect(http.MethodGet, "/path").
	WithBody("hello world!")

func (*Request) WithBodyJSON added in v0.1.2

func (r *Request) WithBodyJSON(v interface{}) *Request

WithBodyJSON marshals the object and use it as the expected body of the given request.

Server.Expect(http.MethodGet, "/path").
	WithBodyJSON(map[string]string{"foo": "bar"})

nolint:unparam

func (*Request) WithHeader

func (r *Request) WithHeader(header, value string) *Request

WithHeader sets an expected header of the given request.

Server.Expect(http.MethodGet, "/path").
	WithHeader("foo": "bar")

func (*Request) WithHeaders

func (r *Request) WithHeaders(headers Header) *Request

WithHeaders sets a list of expected headers of the given request.

Server.Expect(http.MethodGet, "/path").
	WithHeaders(httpmock.Header{"foo": "bar"})

type RequestHandler

type RequestHandler func(r *http.Request) ([]byte, error)

RequestHandler handles the request and returns a result or an error.

type RequestMatcher

type RequestMatcher func(r *http.Request, expectations []*Request) (*Request, []*Request, error)

RequestMatcher matches a request with one of the expectations.

func DefaultRequestMatcher

func DefaultRequestMatcher() RequestMatcher

DefaultRequestMatcher instantiates a SequentialRequestMatcher with ExactURIMatcher, ExactHeaderMatcher and ExactBodyMatcher.

func SequentialRequestMatcher

func SequentialRequestMatcher(options ...RequestMatcherOption) RequestMatcher

SequentialRequestMatcher matches a request in sequence.

type RequestMatcherConfig

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

RequestMatcherConfig is config of RequestMatcher.

func ConfigureRequestMatcher

func ConfigureRequestMatcher(options ...RequestMatcherOption) *RequestMatcherConfig

ConfigureRequestMatcher configures ConfigureRequestMatcher with RequestMatcherOption.

type RequestMatcherError

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

RequestMatcherError represents an error that occurs while matching a request.

func MatcherError

func MatcherError(expected *Request, request *http.Request, message string, args ...interface{}) *RequestMatcherError

MatcherError instantiates a new RequestMatcherError.

func (RequestMatcherError) Error

func (e RequestMatcherError) Error() string

Error satisfies the error interface.

type RequestMatcherOption

type RequestMatcherOption func(c *RequestMatcherConfig)

RequestMatcherOption configures RequestMatcherConfig.

func WithExactBodyMatcher

func WithExactBodyMatcher() RequestMatcherOption

WithExactBodyMatcher sets BodyMatcher to ExactBodyMatcher.

func WithExactHeaderMatcher

func WithExactHeaderMatcher() RequestMatcherOption

WithExactHeaderMatcher sets HeaderMatcher to ExactHeaderMatcher.

func WithExactURIMatcher

func WithExactURIMatcher() RequestMatcherOption

WithExactURIMatcher sets URIMatcher to ExactURIMatcher.

type Server

type Server struct {
	// Represents the requests that are expected of a server.
	ExpectedRequests []*Request

	// Holds the requested that were made to this server.
	Requests []Request
	// contains filtered or unexported fields
}

Server is a Mock server.

func MockServer

func MockServer(t TestingT, mocks ...func(s *Server)) *Server

MockServer creates a mocked server.

func NewServer

func NewServer(t TestingT) *Server

NewServer creates mocked server.

func (*Server) Close

func (s *Server) Close()

Close closes mocked server.

func (*Server) Expect

func (s *Server) Expect(method, requestURI string) *Request

Expect adds a new expected request.

func (*Server) ExpectationsWereMet

func (s *Server) ExpectationsWereMet() error

ExpectationsWereMet checks whether all queued expectations were met in order. If any of them was not met - an error is returned.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP serves the request.

func (*Server) URL

func (s *Server) URL() string

URL returns the current URL of the httptest.Server.

func (*Server) WithDefaultResponseHeaders

func (s *Server) WithDefaultResponseHeaders(headers Header) *Server

WithDefaultResponseHeaders sets the default response headers of the server.

func (*Server) WithRequestMatcher

func (s *Server) WithRequestMatcher(matcher RequestMatcher) *Server

WithRequestMatcher sets the RequestMatcher of the server.

type TestingT

type TestingT interface {
	Errorf(format string, args ...interface{})
	FailNow()
	Cleanup(func())
}

TestingT is an interface wrapper around *testing.T.

type URIMatcher

type URIMatcher func(expected, url string) bool

URIMatcher matches an URI with an expectation.

func ExactURIMatcher

func ExactURIMatcher() URIMatcher

ExactURIMatcher matches an url by checking if it is equal to the expectation.

Jump to

Keyboard shortcuts

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