• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.gitignoreH A D02-May-2019252

.travis.ymlH A D02-May-20191,023

LICENSEH A D02-May-20191.1 KiB

README.mdH A D02-May-20197 KiB

doc.goH A D02-May-20192.8 KiB

env.goH A D02-May-2019239

env_test.goH A D02-May-20191.6 KiB

go.modH A D02-May-201943

response.goH A D02-May-20198.7 KiB

response_test.goH A D02-May-20197.5 KiB

transport.goH A D02-May-201932.5 KiB

transport_test.goH A D02-May-201926.6 KiB

README.md

1# httpmock [![Build Status](https://travis-ci.org/jarcoal/httpmock.png?branch=v1)](https://travis-ci.org/jarcoal/httpmock) [![Coverage Status](https://coveralls.io/repos/github/jarcoal/httpmock/badge.svg?branch=v1)](https://coveralls.io/github/jarcoal/httpmock?branch=v1) [![GoDoc](https://godoc.org/github.com/jarcoal/httpmock?status.svg)](https://godoc.org/github.com/jarcoal/httpmock) [![Version](https://img.shields.io/github/tag/jarcoal/httpmock.svg)](https://github.com/jarcoal/httpmock/releases) [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go/#testing)
2
3Easy mocking of http responses from external resources.
4
5## Install
6
7Currently supports Go 1.7 - 1.12.
8
9`v1` branch has to be used instead of `master`.
10
11
12### Using go modules (aka. `go mod`)
13
14In your go files, simply use:
15```go
16import "github.com/jarcoal/httpmock"
17```
18
19Then next `go mod tidy` or `go test` invocation will automatically
20populate your `go.mod` with the last httpmock release, now
21[![Version](https://img.shields.io/github/tag/jarcoal/httpmock.svg)](https://github.com/jarcoal/httpmock/releases).
22
23Note you can use `go mod vendor` to vendor your dependencies.
24
25
26### Using `$GOPATH`
27
28`v1` branch is configured as the default branch in github, so:
29```
30go get github.com/jarcoal/httpmock
31```
32
33automatically downloads the `v1` branch in `$GOPATH/src`. Then in your
34go files use:
35```go
36import "github.com/jarcoal/httpmock"
37```
38
39
40### Vendoring, using [`govendor`](https://github.com/kardianos/govendor) for example
41
42When vendoring is used, `v1` branch has to be specified. Two choices here:
43
44- preferred way:
45  ```
46  govendor fetch github.com/jarcoal/httpmock@v1
47  ```
48  then in go files:
49  ```go
50  import "github.com/jarcoal/httpmock"
51  ```
52- old way (before `v1` was set as default branch), use gopkg to read from
53  `v1` branch:
54  ```
55  govendor fetch gopkg.in/jarcoal/httpmock.v1
56  ```
57  then in go files:
58  ```go
59  import "gopkg.in/jarcoal/httpmock.v1"
60  ```
61
62
63## Usage
64
65### Simple Example:
66```go
67func TestFetchArticles(t *testing.T) {
68	httpmock.Activate()
69	defer httpmock.DeactivateAndReset()
70
71	// Exact URL match
72	httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles",
73		httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`))
74
75	// Regexp match (could use httpmock.RegisterRegexpResponder instead)
76	httpmock.RegisterResponder("GET", `=~^https://api\.mybiz\.com/articles/id/\d+\z`,
77		httpmock.NewStringResponder(200, `{"id": 1, "name": "My Great Article"}`))
78
79	// do stuff that makes a request to articles
80	...
81
82	// get count info
83	httpmock.GetTotalCallCount()
84
85	// get the amount of calls for the registered responder
86	info := httpmock.GetCallCountInfo()
87	info["GET https://api.mybiz.com/articles"] // number of GET calls made to https://api.mybiz.com/articles
88	info["GET https://api.mybiz.com/articles/id/12"] // number of GET calls made to https://api.mybiz.com/articles/id/12
89	info[`GET =~^https://api\.mybiz\.com/articles/id/\d+\z`] // number of GET calls made to https://api.mybiz.com/articles/id/<any-number>
90}
91```
92
93### Advanced Example:
94```go
95func TestFetchArticles(t *testing.T) {
96	httpmock.Activate()
97	defer httpmock.DeactivateAndReset()
98
99	// our database of articles
100	articles := make([]map[string]interface{}, 0)
101
102	// mock to list out the articles
103	httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles",
104		func(req *http.Request) (*http.Response, error) {
105			resp, err := httpmock.NewJsonResponse(200, articles)
106			if err != nil {
107				return httpmock.NewStringResponse(500, ""), nil
108			}
109			return resp, nil
110		},
111	)
112
113	// return an article related to the request with the help of regexp submatch (\d+)
114	httpmock.RegisterResponder("GET", `=~^https://api\.mybiz\.com/articles/id/(\d+)\z`,
115		func(req *http.Request) (*http.Response, error) {
116			// Get ID from request
117			id := httpmock.MustGetSubmatchAsUint(req, 1) // 1=first regexp submatch
118			return httpmock.NewJsonResponse(200, map[string]interface{}{
119				"id":   id,
120				"name": "My Great Article",
121			})
122		},
123	)
124
125	// mock to add a new article
126	httpmock.RegisterResponder("POST", "https://api.mybiz.com/articles",
127		func(req *http.Request) (*http.Response, error) {
128			article := make(map[string]interface{})
129			if err := json.NewDecoder(req.Body).Decode(&article); err != nil {
130				return httpmock.NewStringResponse(400, ""), nil
131			}
132
133			articles = append(articles, article)
134
135			resp, err := httpmock.NewJsonResponse(200, article)
136			if err != nil {
137				return httpmock.NewStringResponse(500, ""), nil
138			}
139			return resp, nil
140		},
141	)
142
143	// do stuff that adds and checks articles
144}
145```
146
147### Algorithm
148
149When `GET http://example.tld/some/path?b=12&a=foo&a=bar` request is
150caught, all standard responders are checked against the following URL
151or paths, the first match stops the search:
152
1531. `http://example.tld/some/path?b=12&a=foo&a=bar` (original URL)
1541. `http://example.tld/some/path?a=bar&a=foo&b=12` (sorted query params)
1551. `http://example.tld/some/path` (without query params)
1561. `/some/path?b=12&a=foo&a=bar` (original URL without scheme and host)
1571. `/some/path?a=bar&a=foo&b=12` (same, but sorted query params)
1581. `/some/path` (path only)
159
160If no standard responder matched, the regexp responders are checked,
161in the same order, the first match stops the search.
162
163
164### [Ginkgo](https://onsi.github.io/ginkgo/) Example:
165```go
166// article_suite_test.go
167
168import (
169	// ...
170	"github.com/jarcoal/httpmock"
171)
172// ...
173var _ = BeforeSuite(func() {
174	// block all HTTP requests
175	httpmock.Activate()
176})
177
178var _ = BeforeEach(func() {
179	// remove any mocks
180	httpmock.Reset()
181})
182
183var _ = AfterSuite(func() {
184	httpmock.DeactivateAndReset()
185})
186
187
188// article_test.go
189
190import (
191	// ...
192	"github.com/jarcoal/httpmock"
193)
194
195var _ = Describe("Articles", func() {
196	It("returns a list of articles", func() {
197		httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json",
198			httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`))
199
200		// do stuff that makes a request to articles.json
201	})
202})
203```
204
205### [Ginkgo](https://onsi.github.io/ginkgo/) + [Resty](https://github.com/go-resty/resty) Example:
206```go
207// article_suite_test.go
208
209import (
210	// ...
211	"github.com/jarcoal/httpmock"
212	"github.com/go-resty/resty"
213)
214// ...
215var _ = BeforeSuite(func() {
216	// block all HTTP requests
217	httpmock.ActivateNonDefault(resty.DefaultClient.GetClient())
218})
219
220var _ = BeforeEach(func() {
221	// remove any mocks
222	httpmock.Reset()
223})
224
225var _ = AfterSuite(func() {
226	httpmock.DeactivateAndReset()
227})
228
229
230// article_test.go
231
232import (
233	// ...
234	"github.com/jarcoal/httpmock"
235	"github.com/go-resty/resty"
236)
237
238var _ = Describe("Articles", func() {
239	It("returns a list of articles", func() {
240		fixture := `{"status":{"message": "Your message", "code": 200}}`
241		responder := httpmock.NewStringResponder(200, fixture)
242		fakeUrl := "https://api.mybiz.com/articles.json"
243		httpmock.RegisterResponder("GET", fakeUrl, responder)
244
245		// fetch the article into struct
246		articleObject := &models.Article{}
247		_, err := resty.R().SetResult(articleObject).Get(fakeUrl)
248
249		// do stuff with the article object ...
250	})
251})
252```
253