Httpmock
HTTP Mock for Golang
Install / Use
/learn @nhatthm/HttpmockREADME
⚠️ From
v0.9.0, the project will be rebranded togo.nhat.io/httpmock.v.8.xis the last version withgithub.com/nhatthm/httpmock.
HTTP Mock for Golang
httpmock is a mock library implementing httptest.Server to support HTTP behavioral tests.
Table of Contents
Prerequisites
Go >= 1.18
<sub><sup>[table of contents]</sup></sub>
Install
go get go.nhat.io/httpmock
<sub><sup>[table of contents]</sup></sub>
Usage
In a nutshell, the httpmock.Server is wrapper around httptest.Server.
It provides extremely powerful methods to write complex expectations and test scenarios.
For creating a basic server, you can use httpmock.NewServer(). It starts a new HTTP server, and you can write your
expectations right away.
However, if you use it in a test (with a t *testing.T), and want to stop the test when an error occurs (for example,
unexpected requests, can't read request body, etc...), use Server.WithTest(t). At the end of the test, you can
use Server.ExpectationsWereMet() error to check if the server serves all the expectation and there is nothing left.
The approach is similar to stretchr/testify. Also, you need to
close the server with Server.Close(). Luckily, you don't have to do that for every test, there is httpmock.New()
method to start a new server, call Server.ExpectationsWereMet() and close the server at the end of the test,
automatically.
For example:
package main
import (
"testing"
"go.nhat.io/httpmock"
)
func TestSimple(t *testing.T) {
srv := httpmock.New(func(s *httpmock.Server) {
s.ExpectGet("/").
Return("hello world!")
})(t)
// Your request and assertions.
// The server is ready at `srv.URL()`
}
After starting the server, you can use Server.URL() to get the address of the server.
For test table approach, you can use the Server.Mocker, example:
package main
import (
"testing"
"go.nhat.io/httpmock"
)
func TestSimple(t *testing.T) {
testCases := []struct {
scenario string
mockServer httpmock.Mocker
// other input and expectations.
}{
{
scenario: "some scenario",
mockServer: httpmock.New(func(s *httpmock.Server) {
s.ExpectGet("/").
Return("hello world!")
}),
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.scenario, func(t *testing.T) {
t.Parallel()
srv := tc.mockServer(t)
// Your request and assertions.
})
}
}
Further reading:
<sub><sup>[table of contents]</sup></sub>
Match a value
httpmock is using go.nhat.io/matcher for matching values and that
makes httpmock more powerful and convenient than ever. When writing expectations for the header or the payload, you
can use any kind of matchers for your needs.
For example, the Request.WithHeader(header string, value any) means you expect a header that matches a value,
you can put any of these into the value:
| Type | Explanation | Example |
|:----------------------:|:---------------------------------------|:------------------------------------------------------|
| string<br/>[]byte | Match the exact string, case-sensitive | .WithHeader("locale", "en-US") |
| *regexp.Regexp | Match using regexp.Regex.MatchString | .WithHeader("locale", regexp.MustCompile("^en-")) |
| matcher.RegexPattern | Match using regexp.Regex.MatchString | .WithHeader("locale", matcher.RegexPattern("^en-")) |
<sub><sup>[table of contents]</sup></sub>
Exact
matcher.Exact matches a value by
using testify/assert.ObjectsAreEqual().
| Matcher | Input | Result |
|:-------------------------------:|:-----------------:|:-------:|
| matcher.Exact("en-US") | "en-US" | true |
| matcher.Exact("en-US") | "en-us" | false |
| matcher.Exact([]byte("en-US)) | []byte("en-US") | true |
| matcher.Exact([]byte("en-US)) | "en-US" | false |
<sub><sup>[table of contents]</sup></sub>
Regexp
matcher.Regex and matcher.RegexPattern match a value by
using Regexp.MatchString. matcher.Regex
expects a *regexp.Regexp while matcher.RegexPattern expects only a regexp pattern. However, in the end, they are the
same because nhatthm/go-matcher creates a new *regexp.Regexp from the pattern using regexp.MustCompile(pattern).
Notice, if the given input is not a string or []byte, the matcher always fails.
<sub><sup>[table of contents]</sup></sub>
JSON
matcher.JSON matches a value by using swaggest/assertjson.FailNotEqual.
The matcher will marshal the input if it is not a string or a []byte, and then check against the expectation. For
example, the expectation is matcher.JSON(`{"message": "hello"}`)
These inputs match that expectation:
{"message":"hello"}(notice there is no space after the:and it still matches)[]byte(`{"message":"hello"}`)map[string]string{"message": "hello"}- Or any objects that produce the same JSON object after calling
json.Marshal()
You could also ignore some fields that you don't want to match. For example, the expectation
is matcher.JSON(`{"name": "John Doe"}`).If you match it with {"name": "John Doe", "message": "hello"}, that will
fail because the message is unexpected. Therefore,
use matcher.JSON(`{"name": "John Doe", "message": "<ignore-diff>"}`)
The "<ignore-diff>" can be used against any data types, not just the string. For example, {"id": "<ignore-diff>"}
and {"id": 42} is a match.
<sub><sup>[table of contents]</sup></sub>
Custom Matcher
You can use your own matcher as long as it implements
the matcher.Matcher interface.
<sub><sup>[table of contents]</sup></sub>
Expect a request
Request URI
Use the Server.Expect(method string, requestURI any), or Server.Expect[METHOD](requestURI any) to
start a new expectation. You can put a string, a []byte or a matcher.Matcher for
the requestURI. If the value is a string or a []byte, the URI is checked by using the matcher.Exact.
For example:
package main
import (
"testing"
"go.nhat.io/httpmock"
)
func TestSimple(t *testing.T) {
srv := httpmock.New(func(s *httpmock.Server) {
s.ExpectGet("/").
Return("hello world!")
})(t)
// Your request and assertions.
}
<sub><sup>[table of contents]</sup></sub>
Request Header
To check whether the header of the incoming request matches some values. You can use:
Request.WithHeader(key string, value any): to match a single header.Request.WithHeaders(header map[string]any): to match multiple headers.
The value could be string, []byte, or a matcher.Matcher. If the value is a string or
a []byte, the header is checked by using the matcher.Exact.
For example:
package main
import (
"testing"
"go.nhat.io/httpmock"
)
func TestSimple(t *testing.T) {
srv := httpmock.New(func(s *httpmock.Server) {
s.ExpectGet("/").
WithHeader("Authorization", httpmock.RegexPattern("^Bearer "))
})(t)
// Your request and assertions.
}
<sub><sup>[table of contents]</sup></sub>
Request Body
There are several ways to match a request body:
WithBody(body any): The expected body can be astring, a[]byteor amatcher.Matcher. If it is astringor a[]byte, the request body is checked bymatched.Exact.WithBodyf(format string, args ...any): Old schoolfmt.Sprintf()call, the request body is checked bymatched.Exactwith the result fromfmt.Sprintf().WithBodyJSON(body any): The expected body will be marshaled usingjson.Marshal()and the request body is checked bymatched.JSON.
For example:
package main
import (
"testing"
"go.nhat.io/http
Related Skills
node-connect
336.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
xurl
336.5kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
frontend-design
82.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
336.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
