Unit Testing in Golang

Testing your code is as important as writing it in the first place.

So, how do you write unit tests in go? Go provides a testing package, for writing automated test cases.

In the example here, I have also used testify as an assertion library.

Not spending more time let’s get to code.

To begin with lets write a canary test. Here is more on why to write canary tests.

package main

import (
	"testing"
	"github.com/stretchr/testify/assert"
)

func TestStub(t *testing.T) {
	assert.True(t, true, "This is good. Canary test passing")
}

In here, we imported the testing package and testify package which I mentioned above. The TestStub function is our canary test.

When you run “go test” command in the folder where this file resides, you should see that all tests are passing.

Changing true to false in the parameters of above test case should cause test to fail.

If you get the desired behaviour, you are good to move onto writing the tests for the real code you wrote.

Taking a function from Posting a Tweet functionality. We will write a unit test for decodeResponse function

Here is the how the function looks like

func decodeResponse(resp *http.Response, data interface{}) error {
	if resp.StatusCode != 200 {
		return fmt.Errorf("Got %d returned status", resp.StatusCode)
	}
	return json.NewDecoder(resp.Body).Decode(data)
}

(In this example, I have modified the function a little to ease Mocking of response object.)

And here is how the test case looks like


type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }


func TestDecodeResponse(t *testing.T) {
	data := "{\"description\" : \"This a sample json response\"}"
	response := &http.Response{
		StatusCode:      404,
		Body: nopCloser{bytes.NewBufferString("{\"Error Encountered\" : \"We have encountered an Error\"}")},
	}
	err := decodeResponse(response, data)
	assert.NotNil(t, err, "We are expecting error and got one")
	assert.Equal(t, "Got 404 returned status", err.Error())
}

In the test case here we have mocked response and to mock http.Response We need to make sure that Body in response is of type io.ReadCloser. Hence, we created a new type nopCloser and implemented Close() method on it.

Here, we created a response object, which has a status code of 404 and Body which basically/ultimately returns a JSON string. We call the decodeResponse method and it returns us an error since StatusCode is not 200.

Further we assert that our err object is not null and the message is “Got 404 returned status”

Now, “go test” and see it all pass!!

Here is the complete test case file including canary test

package main

import (
	"testing"
	"github.com/stretchr/testify/assert"
	"net/http"
	"bytes"
	"io"
)

func TestStub(t *testing.T) {
	assert.True(t, true, "This is good. Canary test passing")
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

func TestDecodeResponse(t *testing.T) {

	data := "{\"description\" : \"This a sample json response\"}"
	response := &http.Response{
		StatusCode:      404,
		Body: nopCloser{bytes.NewBufferString("{\"Error Encountered\" : \"We have encountered an Error\"}")},
	}
	err := decodeResponse(response, data)
	assert.NotNil(t, err, "We are expecting error and got one")
	assert.Equal(t, "Got 404 returned status", err.Error())
}

So much Fun!

~~ Whizdumb ~~
Email : sachin.xpert@gmail.com

One response

Comments are closed.