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).
4
5Heavily inspired by [nock](https://github.com/node-nock/nock). See also its Python port, [pook](https://github.com/h2non/pook).
6
7Take a look to the [examples](#examples) to get started.
8
9## Features
10
11- Simple, expressive, fluent API.
12- Semantic DSL for easy HTTP mocks definition.
13- Built-in helpers for easy JSON/XML mocking.
14- Supports persistent and volatile mocks.
15- Full regexp capable HTTP request matching.
16- Designed for both testing and runtime scenarios.
17- Match request by method, URL params, headers and bodies.
18- Extensible and pluggable HTTP matching rules.
19- Ability to switch between mock and real networking modes.
20- Ability to filter/map HTTP requests for accurate mock matching.
21- Supports map and filters to handle mocks easily.
22- Wide compatible HTTP interceptor using `http.RoundTripper` interface.
23- Works with any `net/http` compatible client, such as [gentleman](https://github.com/h2non/gentleman).
24- Network delay simulation (beta).
25- Extensible and hackable API.
26- Dependency free.
27
28## Installation
29
30```bash
31go get -u gopkg.in/h2non/gock.v1
32```
33
34## API
35
36See [godoc reference](https://godoc.org/github.com/h2non/gock) for detailed API documentation.
37
38## How it mocks
39
401. Intercepts any HTTP outgoing request via `http.DefaultTransport` or custom `http.Transport` used by any `http.Client`.
412. Matches outgoing HTTP requests against a pool of defined HTTP mock expectations in FIFO declaration order.
423. If at least one mock matches, it will be used in order to compose the mock HTTP response.
434. 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.
44
45## Tips
46
47#### Testing
48
49Declare your mocks before you start declaring the concrete test logic:
50
51```go
52func TestFoo(t *testing.T) {
53 defer gock.Off() // Flush pending mocks after test execution
54
55 gock.New("http://server.com").
56 Get("/bar").
57 Reply(200).
58 JSON(map[string]string{"foo": "bar"})
59
60 // Your test code starts here...
61}
62```
63
64#### Race conditions
65
66If you're running concurrent code, be aware that your mocks are declared first to avoid unexpected
67race conditions while configuring `gock` or intercepting custom HTTP clients.
68
69`gock` is not fully thread-safe, but sensible parts are. Any help making `gock` more reliable in this sense is highly appreciated.
70
71#### Define complex mocks first
72
73If you're mocking a bunch of mocks in the same test suite, it's recommended to define the more
74concrete mocks first, and then the generic ones.
75
76This approach usually avoids matching unexpected generic mocks (e.g: specific header, body payload...) instead of the generic ones that performs less complex matches.
77
78## Examples
79
80See [examples](https://github.com/h2non/gock/tree/master/_examples) directory for more featured use cases.
81
82#### Simple mocking via tests
83
84```go
85package test
86
87import (
88 "github.com/nbio/st"
89 "gopkg.in/h2non/gock.v1"
90 "io/ioutil"
91 "net/http"
92 "testing"
93)
94
95func TestSimple(t *testing.T) {
96 defer gock.Off()
97
98 gock.New("http://foo.com").
99 Get("/bar").
100 Reply(200).
101 JSON(map[string]string{"foo": "bar"})
102
103 res, err := http.Get("http://foo.com/bar")
104 st.Expect(t, err, nil)
105 st.Expect(t, res.StatusCode, 200)
106
107 body, _ := ioutil.ReadAll(res.Body)
108 st.Expect(t, string(body)[:13], `{"foo":"bar"}`)
109
110 // Verify that we don't have pending mocks
111 st.Expect(t, gock.IsDone(), true)
112}
113```
114
115#### Request headers matching
116
117```go
118package test
119
120import (
121 "github.com/nbio/st"
122 "gopkg.in/h2non/gock.v1"
123 "io/ioutil"
124 "net/http"
125 "testing"
126)
127
128func TestMatchHeaders(t *testing.T) {
129 defer gock.Off()
130
131 gock.New("http://foo.com").
132 MatchHeader("Authorization", "^foo bar$").
133 MatchHeader("API", "1.[0-9]+").
134 HeaderPresent("Accept").
135 Reply(200).
136 BodyString("foo foo")
137
138 req, err := http.NewRequest("GET", "http://foo.com", nil)
139 req.Header.Set("Authorization", "foo bar")
140 req.Header.Set("API", "1.0")
141 req.Header.Set("Accept", "text/plain")
142
143 res, err := (&http.Client{}).Do(req)
144 st.Expect(t, err, nil)
145 st.Expect(t, res.StatusCode, 200)
146 body, _ := ioutil.ReadAll(res.Body)
147 st.Expect(t, string(body), "foo foo")
148
149 // Verify that we don't have pending mocks
150 st.Expect(t, gock.IsDone(), true)
151}
152```
153
154#### JSON body matching and response
155
156```go
157package test
158
159import (
160 "bytes"
161 "github.com/nbio/st"
162 "gopkg.in/h2non/gock.v1"
163 "io/ioutil"
164 "net/http"
165 "testing"
166)
167
168func TestMockSimple(t *testing.T) {
169 defer gock.Off()
170
171 gock.New("http://foo.com").
172 Post("/bar").
173 MatchType("json").
174 JSON(map[string]string{"foo": "bar"}).
175 Reply(201).
176 JSON(map[string]string{"bar": "foo"})
177
178 body := bytes.NewBuffer([]byte(`{"foo":"bar"}`))
179 res, err := http.Post("http://foo.com/bar", "application/json", body)
180 st.Expect(t, err, nil)
181 st.Expect(t, res.StatusCode, 201)
182
183 resBody, _ := ioutil.ReadAll(res.Body)
184 st.Expect(t, string(resBody)[:13], `{"bar":"foo"}`)
185
186 // Verify that we don't have pending mocks
187 st.Expect(t, gock.IsDone(), true)
188}
189```
190
191#### Mocking a custom http.Client and http.RoundTripper
192
193```go
194package test
195
196import (
197 "github.com/nbio/st"
198 "gopkg.in/h2non/gock.v1"
199 "io/ioutil"
200 "net/http"
201 "testing"
202)
203
204func TestClient(t *testing.T) {
205 defer gock.Off()
206
207 gock.New("http://foo.com").
208 Reply(200).
209 BodyString("foo foo")
210
211 req, err := http.NewRequest("GET", "http://foo.com", nil)
212 client := &http.Client{Transport: &http.Transport{}}
213 gock.InterceptClient(client)
214
215 res, err := client.Do(req)
216 st.Expect(t, err, nil)
217 st.Expect(t, res.StatusCode, 200)
218 body, _ := ioutil.ReadAll(res.Body)
219 st.Expect(t, string(body), "foo foo")
220
221 // Verify that we don't have pending mocks
222 st.Expect(t, gock.IsDone(), true)
223}
224```
225
226#### Enable real networking
227
228```go
229package main
230
231import (
232 "fmt"
233 "gopkg.in/h2non/gock.v1"
234 "io/ioutil"
235 "net/http"
236)
237
238func main() {
239 defer gock.Off()
240 defer gock.DisableNetworking()
241
242 gock.EnableNetworking()
243 gock.New("http://httpbin.org").
244 Get("/get").
245 Reply(201).
246 SetHeader("Server", "gock")
247
248 res, err := http.Get("http://httpbin.org/get")
249 if err != nil {
250 fmt.Errorf("Error: %s", err)
251 }
252
253 // The response status comes from the mock
254 fmt.Printf("Status: %d\n", res.StatusCode)
255 // The server header comes from mock as well
256 fmt.Printf("Server header: %s\n", res.Header.Get("Server"))
257 // Response body is the original
258 body, _ := ioutil.ReadAll(res.Body)
259 fmt.Printf("Body: %s", string(body))
260
261 // Verify that we don't have pending mocks
262 st.Expect(t, gock.IsDone(), true)
263}
264```
265
266## Hacking it!
267
268You can easily hack `gock` defining custom matcher functions with own matching rules.
269
270See [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.
271
272## License
273
274MIT - Tomas Aparicio
275