httpmock

package module
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: May 2, 2019 License: MIT Imports: 16 Imported by: 172

README

httpmock Build Status Coverage Status GoDoc Version Mentioned in Awesome Go

Easy mocking of http responses from external resources.

Install

Currently supports Go 1.7 - 1.12.

v1 branch has to be used instead of master.

Using go modules (aka. go mod)

In your go files, simply use:

import "github.com/jarcoal/httpmock"

Then next go mod tidy or go test invocation will automatically populate your go.mod with the last httpmock release, now Version.

Note you can use go mod vendor to vendor your dependencies.

Using $GOPATH

v1 branch is configured as the default branch in github, so:

go get github.com/jarcoal/httpmock

automatically downloads the v1 branch in $GOPATH/src. Then in your go files use:

import "github.com/jarcoal/httpmock"
Vendoring, using govendor for example

When vendoring is used, v1 branch has to be specified. Two choices here:

  • preferred way:
    govendor fetch github.com/jarcoal/httpmock@v1
    
    then in go files:
    import "github.com/jarcoal/httpmock"
    
  • old way (before v1 was set as default branch), use gopkg to read from v1 branch:
    govendor fetch gopkg.in/jarcoal/httpmock.v1
    
    then in go files:
    import "gopkg.in/jarcoal/httpmock.v1"
    

Usage

Simple Example:
func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	// Exact URL match
	httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles",
		httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`))

	// Regexp match (could use httpmock.RegisterRegexpResponder instead)
	httpmock.RegisterResponder("GET", `=~^https://api\.mybiz\.com/articles/id/\d+\z`,
		httpmock.NewStringResponder(200, `{"id": 1, "name": "My Great Article"}`))

	// do stuff that makes a request to articles
	...

	// get count info
	httpmock.GetTotalCallCount()

	// get the amount of calls for the registered responder
	info := httpmock.GetCallCountInfo()
	info["GET https://api.mybiz.com/articles"] // number of GET calls made to https://api.mybiz.com/articles
	info["GET https://api.mybiz.com/articles/id/12"] // number of GET calls made to https://api.mybiz.com/articles/id/12
	info[`GET =~^https://api\.mybiz\.com/articles/id/\d+\z`] // number of GET calls made to https://api.mybiz.com/articles/id/<any-number>
}
Advanced Example:
func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	// our database of articles
	articles := make([]map[string]interface{}, 0)

	// mock to list out the articles
	httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles",
		func(req *http.Request) (*http.Response, error) {
			resp, err := httpmock.NewJsonResponse(200, articles)
			if err != nil {
				return httpmock.NewStringResponse(500, ""), nil
			}
			return resp, nil
		},
	)

	// return an article related to the request with the help of regexp submatch (\d+)
	httpmock.RegisterResponder("GET", `=~^https://api\.mybiz\.com/articles/id/(\d+)\z`,
		func(req *http.Request) (*http.Response, error) {
			// Get ID from request
			id := httpmock.MustGetSubmatchAsUint(req, 1) // 1=first regexp submatch
			return httpmock.NewJsonResponse(200, map[string]interface{}{
				"id":   id,
				"name": "My Great Article",
			})
		},
	)

	// mock to add a new article
	httpmock.RegisterResponder("POST", "https://api.mybiz.com/articles",
		func(req *http.Request) (*http.Response, error) {
			article := make(map[string]interface{})
			if err := json.NewDecoder(req.Body).Decode(&article); err != nil {
				return httpmock.NewStringResponse(400, ""), nil
			}

			articles = append(articles, article)

			resp, err := httpmock.NewJsonResponse(200, article)
			if err != nil {
				return httpmock.NewStringResponse(500, ""), nil
			}
			return resp, nil
		},
	)

	// do stuff that adds and checks articles
}
Algorithm

When GET http://example.tld/some/path?b=12&a=foo&a=bar request is caught, all standard responders are checked against the following URL or paths, the first match stops the search:

  1. http://example.tld/some/path?b=12&a=foo&a=bar (original URL)
  2. http://example.tld/some/path?a=bar&a=foo&b=12 (sorted query params)
  3. http://example.tld/some/path (without query params)
  4. /some/path?b=12&a=foo&a=bar (original URL without scheme and host)
  5. /some/path?a=bar&a=foo&b=12 (same, but sorted query params)
  6. /some/path (path only)

If no standard responder matched, the regexp responders are checked, in the same order, the first match stops the search.

Ginkgo Example:
// article_suite_test.go

import (
	// ...
	"github.com/jarcoal/httpmock"
)
// ...
var _ = BeforeSuite(func() {
	// block all HTTP requests
	httpmock.Activate()
})

var _ = BeforeEach(func() {
	// remove any mocks
	httpmock.Reset()
})

var _ = AfterSuite(func() {
	httpmock.DeactivateAndReset()
})


// article_test.go

import (
	// ...
	"github.com/jarcoal/httpmock"
)

var _ = Describe("Articles", func() {
	It("returns a list of articles", func() {
		httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json",
			httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`))

		// do stuff that makes a request to articles.json
	})
})
Ginkgo + Resty Example:
// article_suite_test.go

import (
	// ...
	"github.com/jarcoal/httpmock"
	"github.com/go-resty/resty"
)
// ...
var _ = BeforeSuite(func() {
	// block all HTTP requests
	httpmock.ActivateNonDefault(resty.DefaultClient.GetClient())
})

var _ = BeforeEach(func() {
	// remove any mocks
	httpmock.Reset()
})

var _ = AfterSuite(func() {
	httpmock.DeactivateAndReset()
})


// article_test.go

import (
	// ...
	"github.com/jarcoal/httpmock"
	"github.com/go-resty/resty"
)

var _ = Describe("Articles", func() {
	It("returns a list of articles", func() {
		fixture := `{"status":{"message": "Your message", "code": 200}}`
		responder := httpmock.NewStringResponder(200, fixture)
		fakeUrl := "https://api.mybiz.com/articles.json"
		httpmock.RegisterResponder("GET", fakeUrl, responder)

		// fetch the article into struct
		articleObject := &models.Article{}
		_, err := resty.R().SetResult(articleObject).Get(fakeUrl)

		// do stuff with the article object ...
	})
})

Documentation

Overview

Package httpmock provides tools for mocking HTTP responses.

Simple Example:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	// Exact URL match
	httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles",
		httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`))

	// Regexp match (could use httpmock.RegisterRegexpResponder instead)
	httpmock.RegisterResponder("GET", `=~^https://api\.mybiz\.com/articles/id/\d+\z`,
		httpmock.NewStringResponder(200, `{"id": 1, "name": "My Great Article"}`))

	// do stuff that makes a request to articles

	// get count info
	httpmock.GetTotalCallCount()

	// get the amount of calls for the registered responder
	info := httpmock.GetCallCountInfo()
	info["GET https://api.mybiz.com/articles"]             // number of GET calls made to https://api.mybiz.com/articles
	info["GET https://api.mybiz.com/articles/id/12"]       // number of GET calls made to https://api.mybiz.com/articles/id/12
	info[`GET =~^https://api\.mybiz\.com/articles/id/\d+\z`] // number of GET calls made to https://api.mybiz.com/articles/id/<any-number>
}

Advanced Example:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	// our database of articles
	articles := make([]map[string]interface{}, 0)

	// mock to list out the articles
	httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles",
		func(req *http.Request) (*http.Response, error) {
			resp, err := httpmock.NewJsonResponse(200, articles)
			if err != nil {
				return httpmock.NewStringResponse(500, ""), nil
			}
			return resp, nil
		},
	)

	// return an article related to the request with the help of regexp submatch (\d+)
	httpmock.RegisterResponder("GET", `=~^https://api\.mybiz\.com/articles/id/(\d+)\z`,
		func(req *http.Request) (*http.Response, error) {
			// Get ID from request
			id := httpmock.MustGetSubmatchAsUint(req, 1) // 1=first regexp submatch
			return httpmock.NewJsonResponse(200, map[string]interface{}{
				"id":   id,
				"name": "My Great Article",
			})
		},
	)

	// mock to add a new article
	httpmock.RegisterResponder("POST", "https://api.mybiz.com/articles",
		func(req *http.Request) (*http.Response, error) {
			article := make(map[string]interface{})
			if err := json.NewDecoder(req.Body).Decode(&article); err != nil {
				return httpmock.NewStringResponse(400, ""), nil
			}

			articles = append(articles, article)

			resp, err := httpmock.NewJsonResponse(200, article)
			if err != nil {
				return httpmock.NewStringResponse(500, ""), nil
			}
			return resp, nil
		},
	)

	// do stuff that adds and checks articles
}

Index

Constants

This section is empty.

Variables

View Source
var DefaultTransport = NewMockTransport()

DefaultTransport is the default mock transport used by Activate, Deactivate, Reset, DeactivateAndReset, RegisterResponder, and RegisterNoResponder.

View Source
var ErrSubmatchNotFound = errors.New("submatch not found")

ErrSubmatchNotFound is the error returned by GetSubmatch* functions when the given submatch index cannot be found.

View Source
var InitialTransport = http.DefaultTransport

InitialTransport is a cache of the original transport used so we can put it back when Deactivate is called.

View Source
var NoResponderFound = errors.New("no responder found") // nolint: golint

NoResponderFound is returned when no responders are found for a given HTTP method and URL.

Functions

func Activate

func Activate()

Activate starts the mock environment. This should be called before your tests run. Under the hood this replaces the Transport on the http.DefaultClient with DefaultTransport.

To enable mocks for a test, simply activate at the beginning of a test:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	// all http requests will now be intercepted
}

If you want all of your tests in a package to be mocked, just call Activate from init():

func init() {
	httpmock.Activate()
}

func ActivateNonDefault

func ActivateNonDefault(client *http.Client)

ActivateNonDefault starts the mock environment with a non-default http.Client. This emulates the Activate function, but allows for custom clients that do not use http.DefaultTransport

To enable mocks for a test using a custom client, activate at the beginning of a test:

client := &http.Client{Transport: &http.Transport{TLSHandshakeTimeout: 60 * time.Second}}
httpmock.ActivateNonDefault(client)

func ConnectionFailure

func ConnectionFailure(*http.Request) (*http.Response, error)

ConnectionFailure is a responder that returns a connection failure. This is the default responder, and is called when no other matching responder is found.

func Deactivate

func Deactivate()

Deactivate shuts down the mock environment. Any HTTP calls made after this will use a live transport.

Usually you'll call it in a defer right after activating the mock environment:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.Deactivate()

	// when this test ends, the mock environment will close
}

func DeactivateAndReset

func DeactivateAndReset()

DeactivateAndReset is just a convenience method for calling Deactivate() and then Reset() Happy deferring!

func Disabled

func Disabled() bool

Disabled allows to test whether httpmock is enabled or not. It depends on GONOMOCKS environment variable.

func GetCallCountInfo

func GetCallCountInfo() map[string]int

GetCallCountInfo gets the info on all the calls httpmock has caught since it was activated or reset. The info is returned as a map of the calling keys with the number of calls made to them as their value. The key is the method, a space, and the url all concatenated together.

As a special case, regexp responders generate 2 entries for each call. One for the call caught and the other for the rule that matched. For example:

RegisterResponder("GET", `=~z\.com\z`, NewStringResponder(200, "body"))
http.Get("http://z.com")

will generate the following result:

map[string]int{
  `GET http://z.com`:  1,
  `GET =~z\.com\z`: 1,
}

func GetSubmatch added in v1.0.4

func GetSubmatch(req *http.Request, n int) (string, error)

GetSubmatch has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as a string. Example:

RegisterResponder("GET", `=~^/item/name/([^/]+)\z`,
	func(req *http.Request) (*http.Response, error) {
		name, err := GetSubmatch(req, 1) // 1=first regexp submatch
		if err != nil {
			return nil, err
		}
		return NewJsonResponse(200, map[string]interface{}{
			"id":   123,
			"name": name,
		})
	})

It panics if n < 1. See MustGetSubmatch to avoid testing the returned error.

func GetSubmatchAsFloat added in v1.0.4

func GetSubmatchAsFloat(req *http.Request, n int) (float64, error)

GetSubmatchAsFloat has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as a float64. Example:

RegisterResponder("PATCH", `=~^/item/id/\d+\?height=(\d+(?:\.\d*)?)\z`,
	func(req *http.Request) (*http.Response, error) {
		height, err := GetSubmatchAsFloat(req, 1) // 1=first regexp submatch
		if err != nil {
			return nil, err
		}
		return NewJsonResponse(200, map[string]interface{}{
			"id":     id,
			"name":   "The beautiful name",
			"height": height,
		})
	})

It panics if n < 1. See MustGetSubmatchAsFloat to avoid testing the returned error.

func GetSubmatchAsInt added in v1.0.4

func GetSubmatchAsInt(req *http.Request, n int) (int64, error)

GetSubmatchAsInt has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as an int64. Example:

RegisterResponder("GET", `=~^/item/id/(\d+)\z`,
	func(req *http.Request) (*http.Response, error) {
		id, err := GetSubmatchAsInt(req, 1) // 1=first regexp submatch
		if err != nil {
			return nil, err
		}
		return NewJsonResponse(200, map[string]interface{}{
			"id":   id,
			"name": "The beautiful name",
		})
	})

It panics if n < 1. See MustGetSubmatchAsInt to avoid testing the returned error.

func GetSubmatchAsUint added in v1.0.4

func GetSubmatchAsUint(req *http.Request, n int) (uint64, error)

GetSubmatchAsUint has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as a uint64. Example:

RegisterResponder("GET", `=~^/item/id/(\d+)\z`,
	func(req *http.Request) (*http.Response, error) {
		id, err := GetSubmatchAsUint(req, 1) // 1=first regexp submatch
		if err != nil {
			return nil, err
		}
		return NewJsonResponse(200, map[string]interface{}{
			"id":   id,
			"name": "The beautiful name",
		})
	})

It panics if n < 1. See MustGetSubmatchAsUint to avoid testing the returned error.

func GetTotalCallCount

func GetTotalCallCount() int

GetTotalCallCount gets the total number of calls httpmock has taken since it was activated or reset.

func MustGetSubmatch added in v1.0.4

func MustGetSubmatch(req *http.Request, n int) string

MustGetSubmatch works as GetSubmatch except that it panics in case of error (submatch not found). It has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as a string. Example:

RegisterResponder("GET", `=~^/item/name/([^/]+)\z`,
	func(req *http.Request) (*http.Response, error) {
		name := MustGetSubmatch(req, 1) // 1=first regexp submatch
		return NewJsonResponse(200, map[string]interface{}{
			"id":   123,
			"name": name,
		})
	})

It panics if n < 1.

func MustGetSubmatchAsFloat added in v1.0.4

func MustGetSubmatchAsFloat(req *http.Request, n int) float64

MustGetSubmatchAsFloat works as GetSubmatchAsFloat except that it panics in case of error (submatch not found or invalid float64 format). It has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as a float64. Example:

RegisterResponder("PATCH", `=~^/item/id/\d+\?height=(\d+(?:\.\d*)?)\z`,
	func(req *http.Request) (*http.Response, error) {
		height := MustGetSubmatchAsFloat(req, 1) // 1=first regexp submatch
		return NewJsonResponse(200, map[string]interface{}{
			"id":     id,
			"name":   "The beautiful name",
			"height": height,
		})
	})

It panics if n < 1.

func MustGetSubmatchAsInt added in v1.0.4

func MustGetSubmatchAsInt(req *http.Request, n int) int64

MustGetSubmatchAsInt works as GetSubmatchAsInt except that it panics in case of error (submatch not found or invalid int64 format). It has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as an int64. Example:

RegisterResponder("GET", `=~^/item/id/(\d+)\z`,
	func(req *http.Request) (*http.Response, error) {
		id := MustGetSubmatchAsInt(req, 1) // 1=first regexp submatch
		return NewJsonResponse(200, map[string]interface{}{
			"id":   id,
			"name": "The beautiful name",
		})
	})

It panics if n < 1.

func MustGetSubmatchAsUint added in v1.0.4

func MustGetSubmatchAsUint(req *http.Request, n int) uint64

MustGetSubmatchAsUint works as GetSubmatchAsUint except that it panics in case of error (submatch not found or invalid uint64 format). It has to be used in Responders installed by RegisterRegexpResponder or RegisterResponder + "=~" URL prefix. It allows to retrieve the n-th submatch of the matching regexp, as a uint64. Example:

RegisterResponder("GET", `=~^/item/id/(\d+)\z`,
	func(req *http.Request) (*http.Response, error) {
		id, err := MustGetSubmatchAsUint(req, 1) // 1=first regexp submatch
		return NewJsonResponse(200, map[string]interface{}{
			"id":   id,
			"name": "The beautiful name",
		})
	})

It panics if n < 1.

func NewBytesResponse

func NewBytesResponse(status int, body []byte) *http.Response

NewBytesResponse creates an *http.Response with a body based on the given bytes. Also accepts an http status code.

func NewJsonResponse

func NewJsonResponse(status int, body interface{}) (*http.Response, error)

NewJsonResponse creates an *http.Response with a body that is a json encoded representation of the given interface{}. Also accepts an http status code.

func NewRespBodyFromBytes

func NewRespBodyFromBytes(body []byte) io.ReadCloser

NewRespBodyFromBytes creates an io.ReadCloser from a byte slice that is suitable for use as an http response body.

func NewRespBodyFromString

func NewRespBodyFromString(body string) io.ReadCloser

NewRespBodyFromString creates an io.ReadCloser from a string that is suitable for use as an http response body.

func NewStringResponse

func NewStringResponse(status int, body string) *http.Response

NewStringResponse creates an *http.Response with a body based on the given string. Also accepts an http status code.

func NewXmlResponse

func NewXmlResponse(status int, body interface{}) (*http.Response, error)

NewXmlResponse creates an *http.Response with a body that is an xml encoded representation of the given interface{}. Also accepts an http status code.

func RegisterNoResponder

func RegisterNoResponder(responder Responder)

RegisterNoResponder adds a mock that will be called whenever a request for an unregistered URL is received. The default behavior is to return a connection error.

In some cases you may not want all URLs to be mocked, in which case you can do this:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()
	httpmock.RegisterNoResponder(httpmock.InitialTransport.RoundTrip)

	// any requests that don't have a registered URL will be fetched normally
}

func RegisterRegexpResponder added in v1.0.4

func RegisterRegexpResponder(method string, urlRegexp *regexp.Regexp, responder Responder)

RegisterRegexpResponder adds a new responder, associated with a given HTTP method and URL (or path) regular expression.

When a request comes in that matches, the responder will be called and the response returned to the client.

As 2 regexps can match the same URL, the regexp responders are tested in the order they are registered. Registering an already existing regexp responder (same method & same regexp string) replaces its responder but does not change its position.

A "=~" prefix is added to the stringified regexp in the statistics returned by GetCallCountInfo().

See RegisterResponder function and the "=~" prefix in its url parameter to avoid compiling the regexp by yourself.

func RegisterResponder

func RegisterResponder(method, url string, responder Responder)

RegisterResponder adds a new responder, associated with a given HTTP method and URL (or path).

When a request comes in that matches, the responder will be called and the response returned to the client.

If url contains query parameters, their order matters as well as their content. All following URLs are here considered as different:

http://z.tld?a=1&b=1
http://z.tld?b=1&a=1
http://z.tld?a&b
http://z.tld?a=&b=

If url begins with "=~", the following chars are considered as a regular expression. If this regexp can not be compiled, it panics. Note that the "=~" prefix remains in statistics returned by GetCallCountInfo(). As 2 regexps can match the same URL, the regexp responders are tested in the order they are registered. Registering an already existing regexp responder (same method & same regexp string) replaces its responder but does not change its position.

See RegisterRegexpResponder() to directly pass a *regexp.Regexp.

Example:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	httpmock.RegisterResponder("GET", "http://example.com/",
		httpmock.NewStringResponder(200, "hello world"))

	httpmock.RegisterResponder("GET", "/path/only",
		httpmock.NewStringResponder("any host hello world", 200))

	httpmock.RegisterResponder("GET", `=~^/item/id/\d+\z`,
		httpmock.NewStringResponder("any item get", 200))

	// requests to http://example.com/ will now return "hello world" and
	// requests to any host with path /path/only will return "any host hello world"
	// requests to any host with path matching ^/item/id/\d+\z regular expression will return "any item get"
}

func RegisterResponderWithQuery

func RegisterResponderWithQuery(method, path string, query interface{}, responder Responder)

RegisterResponderWithQuery it is same as RegisterResponder, but doesn't depends on query items order.

query type can be:

url.Values
map[string]string
string, a query string like "a=12&a=13&b=z&c" (see net/url.ParseQuery function)

If the query type is not recognized or the string cannot be parsed using net/url.ParseQuery, a panic() occurs.

Example using a net/url.Values:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	expectedQuery := net.Values{
		"a": []string{"3", "1", "8"},
		"b": []string{"4", "2"},
	}
	httpmock.RegisterResponderWithQueryValues("GET", "http://example.com/", expectedQuery,
		httpmock.NewStringResponder("hello world", 200))

	// requests to http://example.com?a=1&a=3&a=8&b=2&b=4
	//      and to http://example.com?b=4&a=2&b=2&a=8&a=1
	// will now return 'hello world'
}

or using a map[string]string:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	expectedQuery := map[string]string{
		"a": "1",
		"b": "2"
	}
	httpmock.RegisterResponderWithQuery("GET", "http://example.com/", expectedQuery,
		httpmock.NewStringResponder("hello world", 200))

	// requests to http://example.com?a=1&b=2 and http://example.com?b=2&a=1 will now return 'hello world'
}

or using a query string:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	expectedQuery := "a=3&b=4&b=2&a=1&a=8"
	httpmock.RegisterResponderWithQueryValues("GET", "http://example.com/", expectedQuery,
		httpmock.NewStringResponder("hello world", 200))

	// requests to http://example.com?a=1&a=3&a=8&b=2&b=4
	//      and to http://example.com?b=4&a=2&b=2&a=8&a=1
	// will now return 'hello world'
}

func Reset

func Reset()

Reset will remove any registered mocks and return the mock environment to it's initial state.

Types

type MockTransport

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

MockTransport implements http.RoundTripper, which fulfills single http requests issued by an http.Client. This implementation doesn't actually make the call, instead deferring to the registered list of responders.

func NewMockTransport

func NewMockTransport() *MockTransport

NewMockTransport creates a new *MockTransport with no responders.

func (*MockTransport) GetCallCountInfo

func (m *MockTransport) GetCallCountInfo() map[string]int

GetCallCountInfo gets the info on all the calls httpmock has caught since it was activated or reset. The info is returned as a map of the calling keys with the number of calls made to them as their value. The key is the method, a space, and the url all concatenated together.

As a special case, regexp responders generate 2 entries for each call. One for the call caught and the other for the rule that matched. For example:

RegisterResponder("GET", `=~z\.com\z`, NewStringResponder(200, "body"))
http.Get("http://z.com")

will generate the following result:

map[string]int{
  `GET http://z.com`:  1,
  `GET =~z\.com\z`: 1,
}

func (*MockTransport) GetTotalCallCount

func (m *MockTransport) GetTotalCallCount() int

GetTotalCallCount returns the totalCallCount.

func (*MockTransport) RegisterNoResponder

func (m *MockTransport) RegisterNoResponder(responder Responder)

RegisterNoResponder is used to register a responder that will be called if no other responder is found. The default is ConnectionFailure.

func (*MockTransport) RegisterRegexpResponder added in v1.0.4

func (m *MockTransport) RegisterRegexpResponder(method string, urlRegexp *regexp.Regexp, responder Responder)

RegisterRegexpResponder adds a new responder, associated with a given HTTP method and URL (or path) regular expression.

When a request comes in that matches, the responder will be called and the response returned to the client.

As 2 regexps can match the same URL, the regexp responders are tested in the order they are registered. Registering an already existing regexp responder (same method & same regexp string) replaces its responder but does not change its position.

A "=~" prefix is added to the stringified regexp in the statistics returned by GetCallCountInfo().

See RegisterResponder function and the "=~" prefix in its url parameter to avoid compiling the regexp by yourself.

func (*MockTransport) RegisterResponder

func (m *MockTransport) RegisterResponder(method, url string, responder Responder)

RegisterResponder adds a new responder, associated with a given HTTP method and URL (or path).

When a request comes in that matches, the responder will be called and the response returned to the client.

If url contains query parameters, their order matters as well as their content. All following URLs are here considered as different:

http://z.tld?a=1&b=1
http://z.tld?b=1&a=1
http://z.tld?a&b
http://z.tld?a=&b=

If url begins with "=~", the following chars are considered as a regular expression. If this regexp can not be compiled, it panics. Note that the "=~" prefix remains in statistics returned by GetCallCountInfo(). As 2 regexps can match the same URL, the regexp responders are tested in the order they are registered. Registering an already existing regexp responder (same method & same regexp string) replaces its responder but does not change its position.

See RegisterRegexpResponder() to directly pass a *regexp.Regexp.

Example:

func TestFetchArticles(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	httpmock.RegisterResponder("GET", "http://example.com/",
		httpmock.NewStringResponder(200, "hello world"))

	httpmock.RegisterResponder("GET", "/path/only",
		httpmock.NewStringResponder("any host hello world", 200))

	httpmock.RegisterResponder("GET", `=~^/item/id/\d+\z`,
		httpmock.NewStringResponder("any item get", 200))

	// requests to http://example.com/ will now return "hello world" and
	// requests to any host with path /path/only will return "any host hello world"
	// requests to any host with path matching ^/item/id/\d+\z regular expression will return "any item get"
}

func (*MockTransport) RegisterResponderWithQuery

func (m *MockTransport) RegisterResponderWithQuery(method, path string, query interface{}, responder Responder)

RegisterResponderWithQuery is same as RegisterResponder, but it doesn't depend on query items order.

If query is non-nil, its type can be:

url.Values
map[string]string
string, a query string like "a=12&a=13&b=z&c" (see net/url.ParseQuery function)

If the query type is not recognized or the string cannot be parsed using net/url.ParseQuery, a panic() occurs.

Unlike RegisterResponder, path cannot be prefixed by "=~" to say it is a regexp. If it is, a panic occurs.

func (*MockTransport) Reset

func (m *MockTransport) Reset()

Reset removes all registered responders (including the no responder) from the MockTransport

func (*MockTransport) RoundTrip

func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip receives HTTP requests and routes them to the appropriate responder. It is required to implement the http.RoundTripper interface. You will not interact with this directly, instead the *http.Client you are using will call it for you.

type Responder

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

Responder is a callback that receives and http request and returns a mocked response.

func NewBytesResponder

func NewBytesResponder(status int, body []byte) Responder

NewBytesResponder creates a Responder from a given body (as a byte slice) and status code.

func NewErrorResponder

func NewErrorResponder(err error) Responder

NewErrorResponder creates a Responder that returns an empty request and the given error. This can be used to e.g. imitate more deep http errors for the client.

func NewJsonResponder

func NewJsonResponder(status int, body interface{}) (Responder, error)

NewJsonResponder creates a Responder from a given body (as an interface{} that is encoded to json) and status code.

func NewJsonResponderOrPanic

func NewJsonResponderOrPanic(status int, body interface{}) Responder

NewJsonResponderOrPanic is like NewJsonResponder but panics in case of error.

It simplifies the call of RegisterResponder, avoiding the use of a temporary variable and an error check, and so can be used as NewStringResponder or NewBytesResponder in such context:

RegisterResponder(
  "GET",
  "/test/path",
  NewJSONResponderOrPanic(200, &MyBody),
)

func NewNotFoundResponder added in v1.0.2

func NewNotFoundResponder(fn func(...interface{})) Responder

NewNotFoundResponder creates a Responder typically used in conjunction with RegisterNoResponder() function and testing package, to be proactive when a Responder is not found. fn is called with a unique string parameter containing the name of the missing route and the stack trace to localize the origin of the call. If fn returns (= if it does not panic), the responder returns an error of the form: "Responder not found for GET http://foo.bar/path". Note that fn can be nil.

It is useful when writing tests to ensure that all routes have been mocked.

Example of use:

import "testing"
...
func TestMyApp(t *testing.T) {
	...
	// Calls testing.Fatal with the name of Responder-less route and
	// the stack trace of the call.
	httpmock.RegisterNoResponder(httpmock.NewNotFoundResponder(t.Fatal))

Will abort the current test and print something like:

transport_test.go:735: Called from net/http.Get()
      at /go/src/github.com/jarcoal/httpmock/transport_test.go:714
    github.com/jarcoal/httpmock.TestCheckStackTracer()
      at /go/src/testing/testing.go:865
    testing.tRunner()
      at /go/src/runtime/asm_amd64.s:1337

func NewStringResponder

func NewStringResponder(status int, body string) Responder

NewStringResponder creates a Responder from a given body (as a string) and status code.

func NewXmlResponder

func NewXmlResponder(status int, body interface{}) (Responder, error)

NewXmlResponder creates a Responder from a given body (as an interface{} that is encoded to xml) and status code.

func NewXmlResponderOrPanic

func NewXmlResponderOrPanic(status int, body interface{}) Responder

NewXmlResponderOrPanic is like NewXmlResponder but panics in case of error.

It simplifies the call of RegisterResponder, avoiding the use of a temporary variable and an error check, and so can be used as NewStringResponder or NewBytesResponder in such context:

RegisterResponder(
  "GET",
  "/test/path",
  NewXmlResponderOrPanic(200, &MyBody),
)

func ResponderFromResponse

func ResponderFromResponse(resp *http.Response) Responder

ResponderFromResponse wraps an *http.Response in a Responder

func (Responder) Once added in v1.0.3

func (r Responder) Once(fn ...func(...interface{})) Responder

Once returns a new Responder callable once before returning an error. If the Responder is called 2 or more times and fn is passed and non-nil, it acts as the fn parameter of NewNotFoundResponder, allowing to dump the stack trace to localize the origin of the call.

func (Responder) Times added in v1.0.3

func (r Responder) Times(n int, fn ...func(...interface{})) Responder

Times returns a Responder callable n times before returning an error. If the Responder is called more than n times and fn is passed and non-nil, it acts as the fn parameter of NewNotFoundResponder, allowing to dump the stack trace to localize the origin of the call.

func (Responder) Trace added in v1.0.3

func (r Responder) Trace(fn func(...interface{})) Responder

Trace returns a new Responder that allow to easily trace the calls of the original Responder using fn. It can be used in conjunction with the testing package as in the example below with the help of (*testing.T).Log method:

import "testing"
...
func TestMyApp(t *testing.T) {
	...
	httpmock.RegisterResponder("GET", "/foo/bar",
 	httpmock.NewStringResponder(200, "{}").Trace(t.Log),
	)

Jump to

Keyboard shortcuts

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