Goal of this package is to provide a small controller to isolate testing of
services (gateways) by mocking the network communication using gock
.
Note: Since the controller is focused on testing, it does not support the
same networking and observation features of gock
and requires manual
transport interception setup. However, the interface is mainly compatible.
Just create a new controller on each test, connect it to your HTTP clients or client wrappers, and then use it to create HTTP mock request/response cycles as usual.
func TestUnit(t *testing.T) {
// Given
gock := gock.NewController(t)
client := &http.Client{}
gock.InterceptClient(client)
gock.New("http://foo.com").Get("/bar").Times(1).
Reply(200).BodyString("result")
// When
...
}
The controller is fully integrated in to the mock
-framework, so
that you can just request the controller via the gomock
constructor
mock.Get(mocks, gock.NewGock)
(see
Example)
Migration from gock
to this package is straight forward. You just add
the controller creation at the begin of your test giving it the name gock
and
hand it over to all methods creating HTTP request/response mocks. The mock
creation than happens as usual.
func TestUnit(t *testing.T) {
// Given
gock := gock.NewController(t)
...
gock.New("http://foo.com").Get("/bar").Times(1).
Reply(200).BodyString("result")
// WHen
...
}
Since the controller does not intercept all transports by default, you need to
setup transport interception manually. This can happen in three different ways.
If you have access to the HTTP request/response client, you can use the usual
InterceptClient
(and RestoreClient
) methods.
func TestUnit(t *testing.T) {
// Given
gock := tock.Controller(t)
...
client := &http.Client{}
gock.InterceptClient(client)
defer gock.RestoreClient(client) // optional
// When
...
}
Customized HTTP clients e.g. resty
may not give direct access to the
transport but offer the ability to set a http.RoundTripper
. The controller
implements this interface and therefore can be simply used as drop in entity.
func TestUnit(t *testing.T) {
// Given
gock := tock.Controller(t)
...
client := resty.New()
client.setTransport(gock)
// When
...
}
As a last resort, you can also intercept the http.DefaultTransport
, however,
this is not advised, since it will destroy the test isolation that is goal of
this controller framework. In this case you should use gock
directly.
The Gock
-controller framework supports a simple integration with the
mock
framework for gomock: it simply provides constructor
that accepts the gomock
-controller. Using constructor, it is possible to
create the usual setup methods similar as described in the
generic mock service call pattern.
func GockCall(
url, path string, input..., status int, output..., error,
) mock.SetupFunc {
return func(mocks *Mocks) any {
mock.Get(mocks, gock.NewGock).New(url).Get(path).Times(1).
Reply(status)...
return nil
}
}
Note: While this already nicely integrates the mock controller creation,
call setup, and validation, it currently provides no support for call order
validation as gomock
supports it.