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

..03-May-2022-

_examples/H03-Aug-2021-

.editorconfigH A D03-Aug-2021186

.gitignoreH A D03-Aug-2021299

.travis.ymlH A D03-Aug-2021745

History.mdH A D03-Aug-20213.6 KiB

LICENSEH A D03-Aug-20211.1 KiB

README.mdH A D03-Aug-20219.7 KiB

go.modH A D03-Aug-2021166

gock.goH A D03-Aug-20214.5 KiB

gock_test.goH A D03-Aug-202111.1 KiB

matcher.goH A D03-Aug-20213.3 KiB

matcher_test.goH A D03-Aug-20214.1 KiB

matchers.goH A D03-Aug-20216.3 KiB

matchers_test.goH A D03-Aug-20217.2 KiB

mock.goH A D03-Aug-20213.7 KiB

mock_test.goH A D03-Aug-20213.1 KiB

options.goH A D03-Aug-2021300

request.goH A D03-Aug-20219.1 KiB

request_test.goH A D03-Aug-20217 KiB

responder.goH A D03-Aug-20212.5 KiB

responder_test.goH A D03-Aug-20213.2 KiB

response.goH A D03-Aug-20214.8 KiB

response_test.goH A D03-Aug-20213.6 KiB

store.goH A D03-Aug-20211.9 KiB

store_test.goH A D03-Aug-20211.6 KiB

transport.goH A D03-Aug-20212.8 KiB

transport_test.goH A D03-Aug-20211.1 KiB

version.goH A D03-Aug-202195

README.md

1# gock [![Build Status](https://travis-ci.org/h2non/gock.svg?branch=master)](https://travis-ci.org/h2non/gock) [![GitHub release](https://img.shields.io/badge/version-v1.0-orange.svg?style=flat)](https://github.com/h2non/gock/releases) [![GoDoc](https://godoc.org/github.com/h2non/gock?status.svg)](https://godoc.org/github.com/h2non/gock) [![Coverage Status](https://coveralls.io/repos/github/h2non/gock/badge.svg?branch=master)](https://coveralls.io/github/h2non/gock?branch=master) [![Go Report Card](https://img.shields.io/badge/go_report-A+-brightgreen.svg)](https://goreportcard.com/report/github.com/h2non/gock) [![license](https://img.shields.io/badge/license-MIT-blue.svg)]()
2
3Versatile HTTP mocking made easy in [Go](https://golang.org) that works with any `net/http` based stdlib implementation.
4
5Heavily inspired by [nock](https://github.com/node-nock/nock).
6There is also its Python port, [pook](https://github.com/h2non/pook).
7
8To get started, take a look to the [examples](#examples).
9
10## Features
11
12- Simple, expressive, fluent API.
13- Semantic API DSL for declarative HTTP mock declarations.
14- Built-in helpers for easy JSON/XML mocking.
15- Supports persistent and volatile TTL-limited mocks.
16- Full regular expressions capable HTTP request mock matching.
17- Designed for both testing and runtime scenarios.
18- Match request by method, URL params, headers and bodies.
19- Extensible and pluggable HTTP matching rules.
20- Ability to switch between mock and real networking modes.
21- Ability to filter/map HTTP requests for accurate mock matching.
22- Supports map and filters to handle mocks easily.
23- Wide compatible HTTP interceptor using `http.RoundTripper` interface.
24- Works with any `net/http` compatible client, such as [gentleman](https://github.com/h2non/gentleman).
25- Network timeout/cancelation delay simulation.
26- Extensible and hackable API.
27- Dependency free.
28
29## Installation
30
31```bash
32go get -u gopkg.in/h2non/gock.v1
33```
34
35## API
36
37See [godoc reference](https://godoc.org/github.com/h2non/gock) for detailed API documentation.
38
39## How it mocks
40
411. Intercepts any HTTP outgoing request via `http.DefaultTransport` or custom `http.Transport` used by any `http.Client`.
422. Matches outgoing HTTP requests against a pool of defined HTTP mock expectations in FIFO declaration order.
433. If at least one mock matches, it will be used in order to compose the mock HTTP response.
444. If no mock can be matched, it will resolve the request with an error, unless real networking mode is enable, in which case a real HTTP request will be performed.
45
46## Tips
47
48#### Testing
49
50Declare your mocks before you start declaring the concrete test logic:
51
52```go
53func TestFoo(t *testing.T) {
54  defer gock.Off() // Flush pending mocks after test execution
55
56  gock.New("http://server.com").
57    Get("/bar").
58    Reply(200).
59    JSON(map[string]string{"foo": "bar"})
60
61  // Your test code starts here...
62}
63```
64
65#### Race conditions
66
67If you're running concurrent code, be aware that your mocks are declared first to avoid unexpected
68race conditions while configuring `gock` or intercepting custom HTTP clients.
69
70`gock` is not fully thread-safe, but sensible parts are.
71Any help making `gock` more reliable in this sense is appreciated.
72
73#### Define complex mocks first
74
75If you're mocking a bunch of mocks in the same test suite, it's recommended to define the more
76concrete mocks first, and then the generic ones.
77
78This approach usually avoids matching unexpected generic mocks (e.g: specific header, body payload...) instead of the generic ones that performs less complex matches.
79
80#### Disable `gock` traffic interception once done
81
82In other to minimize potential side effects within your test code, it's a good practice
83disabling `gock` once you are done with your HTTP testing logic.
84
85A Go idiomatic approach for doing this can be using it in a `defer` statement, such as:
86
87```go
88func TestGock (t *testing.T) {
89	defer gock.Off()
90
91	// ... my test code goes here
92}
93```
94
95#### Intercept an `http.Client` just once
96
97You don't need to intercept multiple times the same `http.Client` instance.
98
99Just call `gock.InterceptClient(client)` once, typically at the beginning of your test scenarios.
100
101#### Restore an `http.Client` after interception
102
103**NOTE**: this is not required is you are using `http.DefaultClient` or `http.DefaultTransport`.
104
105As a good testing pattern, you should call `gock.RestoreClient(client)` after running your test scenario, typically as after clean up hook.
106
107You can also use a `defer` statement for doing it, as you do with `gock.Off()`, such as:
108
109```go
110func TestGock (t *testing.T) {
111	defer gock.Off()
112	defer gock.RestoreClient(client)
113
114	// ... my test code goes here
115}
116```
117
118## Examples
119
120See [examples](https://github.com/h2non/gock/tree/master/_examples) directory for more featured use cases.
121
122#### Simple mocking via tests
123
124```go
125package test
126
127import (
128  "github.com/nbio/st"
129  "gopkg.in/h2non/gock.v1"
130  "io/ioutil"
131  "net/http"
132  "testing"
133)
134
135func TestSimple(t *testing.T) {
136  defer gock.Off()
137
138  gock.New("http://foo.com").
139    Get("/bar").
140    Reply(200).
141    JSON(map[string]string{"foo": "bar"})
142
143  res, err := http.Get("http://foo.com/bar")
144  st.Expect(t, err, nil)
145  st.Expect(t, res.StatusCode, 200)
146
147  body, _ := ioutil.ReadAll(res.Body)
148  st.Expect(t, string(body)[:13], `{"foo":"bar"}`)
149
150  // Verify that we don't have pending mocks
151  st.Expect(t, gock.IsDone(), true)
152}
153```
154
155#### Request headers matching
156
157```go
158package test
159
160import (
161  "github.com/nbio/st"
162  "gopkg.in/h2non/gock.v1"
163  "io/ioutil"
164  "net/http"
165  "testing"
166)
167
168func TestMatchHeaders(t *testing.T) {
169  defer gock.Off()
170
171  gock.New("http://foo.com").
172    MatchHeader("Authorization", "^foo bar$").
173    MatchHeader("API", "1.[0-9]+").
174    HeaderPresent("Accept").
175    Reply(200).
176    BodyString("foo foo")
177
178  req, err := http.NewRequest("GET", "http://foo.com", nil)
179  req.Header.Set("Authorization", "foo bar")
180  req.Header.Set("API", "1.0")
181  req.Header.Set("Accept", "text/plain")
182
183  res, err := (&http.Client{}).Do(req)
184  st.Expect(t, err, nil)
185  st.Expect(t, res.StatusCode, 200)
186  body, _ := ioutil.ReadAll(res.Body)
187  st.Expect(t, string(body), "foo foo")
188
189  // Verify that we don't have pending mocks
190  st.Expect(t, gock.IsDone(), true)
191}
192```
193
194#### Request param matching
195
196```go
197package test
198
199import (
200  "github.com/nbio/st"
201  "gopkg.in/h2non/gock.v1"
202  "io/ioutil"
203  "net/http"
204  "testing"
205)
206
207func TestMatchParams(t *testing.T) {
208  defer gock.Off()
209
210  gock.New("http://foo.com").
211    MatchParam("page", "1").
212    MatchParam("per_page", "10").
213    Reply(200).
214    BodyString("foo foo")
215
216  req, err := http.NewRequest("GET", "http://foo.com?page=1&per_page=10", nil)
217
218  res, err := (&http.Client{}).Do(req)
219  st.Expect(t, err, nil)
220  st.Expect(t, res.StatusCode, 200)
221  body, _ := ioutil.ReadAll(res.Body)
222  st.Expect(t, string(body), "foo foo")
223
224  // Verify that we don't have pending mocks
225  st.Expect(t, gock.IsDone(), true)
226}
227```
228
229#### JSON body matching and response
230
231```go
232package test
233
234import (
235  "bytes"
236  "github.com/nbio/st"
237  "gopkg.in/h2non/gock.v1"
238  "io/ioutil"
239  "net/http"
240  "testing"
241)
242
243func TestMockSimple(t *testing.T) {
244  defer gock.Off()
245
246  gock.New("http://foo.com").
247    Post("/bar").
248    MatchType("json").
249    JSON(map[string]string{"foo": "bar"}).
250    Reply(201).
251    JSON(map[string]string{"bar": "foo"})
252
253  body := bytes.NewBuffer([]byte(`{"foo":"bar"}`))
254  res, err := http.Post("http://foo.com/bar", "application/json", body)
255  st.Expect(t, err, nil)
256  st.Expect(t, res.StatusCode, 201)
257
258  resBody, _ := ioutil.ReadAll(res.Body)
259  st.Expect(t, string(resBody)[:13], `{"bar":"foo"}`)
260
261  // Verify that we don't have pending mocks
262  st.Expect(t, gock.IsDone(), true)
263}
264```
265
266#### Mocking a custom http.Client and http.RoundTripper
267
268```go
269package test
270
271import (
272  "github.com/nbio/st"
273  "gopkg.in/h2non/gock.v1"
274  "io/ioutil"
275  "net/http"
276  "testing"
277)
278
279func TestClient(t *testing.T) {
280  defer gock.Off()
281
282  gock.New("http://foo.com").
283    Reply(200).
284    BodyString("foo foo")
285
286  req, err := http.NewRequest("GET", "http://foo.com", nil)
287  client := &http.Client{Transport: &http.Transport{}}
288  gock.InterceptClient(client)
289
290  res, err := client.Do(req)
291  st.Expect(t, err, nil)
292  st.Expect(t, res.StatusCode, 200)
293  body, _ := ioutil.ReadAll(res.Body)
294  st.Expect(t, string(body), "foo foo")
295
296  // Verify that we don't have pending mocks
297  st.Expect(t, gock.IsDone(), true)
298}
299```
300
301#### Enable real networking
302
303```go
304package main
305
306import (
307  "fmt"
308  "gopkg.in/h2non/gock.v1"
309  "io/ioutil"
310  "net/http"
311)
312
313func main() {
314  defer gock.Off()
315  defer gock.DisableNetworking()
316
317  gock.EnableNetworking()
318  gock.New("http://httpbin.org").
319    Get("/get").
320    Reply(201).
321    SetHeader("Server", "gock")
322
323  res, err := http.Get("http://httpbin.org/get")
324  if err != nil {
325    fmt.Errorf("Error: %s", err)
326  }
327
328  // The response status comes from the mock
329  fmt.Printf("Status: %d\n", res.StatusCode)
330  // The server header comes from mock as well
331  fmt.Printf("Server header: %s\n", res.Header.Get("Server"))
332  // Response body is the original
333  body, _ := ioutil.ReadAll(res.Body)
334  fmt.Printf("Body: %s", string(body))
335}
336```
337
338#### Debug intercepted http requests
339
340```go
341package main
342
343import (
344	"bytes"
345	"gopkg.in/h2non/gock.v1"
346	"net/http"
347)
348
349func main() {
350	defer gock.Off()
351	gock.Observe(gock.DumpRequest)
352
353	gock.New("http://foo.com").
354		Post("/bar").
355		MatchType("json").
356		JSON(map[string]string{"foo": "bar"}).
357		Reply(200)
358
359	body := bytes.NewBuffer([]byte(`{"foo":"bar"}`))
360	http.Post("http://foo.com/bar", "application/json", body)
361}
362
363```
364
365## Hacking it!
366
367You can easily hack `gock` defining custom matcher functions with own matching rules.
368
369See [add matcher functions](https://github.com/h2non/gock/blob/master/_examples/add_matchers/matchers.go) and [custom matching layer](https://github.com/h2non/gock/blob/master/_examples/custom_matcher/matcher.go) examples for further details.
370
371## License
372
373MIT - Tomas Aparicio
374