HTTPMock for Testing a Golang API Client

I'm working on an API client for some Nexmo APIs and having tests to work through the various responses that the API can return and check that it does what I expect has been very handy so I thought I'd share my thoughts. I've got a bit of a head start here too since the OpenAPI specs have example responses in them that I can grab and feed to the mocking tool I'm using in my tests!

For Golang, I'm using HTTPMock. It allows me to configure a particular response to send when a particular request is received. In fact, you can queue up a few responses but I'm writing a really thin API client so nothing needs more than one call so far.

Inside each test, I configure the request to respond to and the response to send, something like this:

httpmock.Activate()
defer httpmock.DeactivateAndReset()

httpmock.RegisterResponder("GET", "https://api.nexmo.com/verify/json",
	func(req *http.Request) (*http.Response, error) {
		resp := httpmock.NewStringResponse(200, `
{
	"request_id": "abcdef0123456789abcdef0123456789",
	"status": "0"
}
`,
		)

		resp.Header.Add("Content-Type", "application/json")
		return resp, nil
	},
)

What's great about this is that the rest of my test looks "normal" - this tool hijacks the web requests my code would have made, and returns its own responses instead. So I go ahead and put in the test basically the code I'd put in an application that used the library I'm working on.

auth := CreateAuthFromKeySecret("12345678", "456")
client := NewVerifyClient(auth)
// the next line calls the code that actually makes the HTTP request that HTTPMock answers
response, _, _ := client.Request("44777000777", "NexmoGoTest", VerifyOpts{})

message := "Request ID: " + response.RequestId
if message != "Request ID: abcdef0123456789abcdef0123456789" {
	t.Errorf("Verify request failed")
}

In contrast to the other languages I've used with XUnit-type testing, golang doesn't really use the "assert" approach for testing, the idea is that you write code and if it doesn't work, there's your error. There are assertion libraries around but since I'm writing all new tests for basically new code, I thought I'd try "the go way" and see how it worked out. So far it's definitely a new way of thinking but I feel equally confident in the tests I'm creating.

The magic really comes when I start adding failure cases to the tests, that way I can check that things fail the way I'd expect - and of course I can invent responses that the API should never be sending and check that the code also copes with the unexpected!


Also published on Medium.

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

This site uses Akismet to reduce spam. Learn how your comment data is processed.