Monday 28 October 2013

Go Package set up with testing in mind

Hi all,

I am going to attempt to explain how to set up a package in Go with the option to Mock the methods in the package for testing. I say attempt because I am still learning Go and the best practice way of doing things, so apologies in advance.

This link to stretchr/testify is required for the following examples. A massive thanks to these guys for making my life a lot easier.

I am going to use very simple examples and more comment the structure than anything, will post an update of code once completed.

So first thing, want to create a package that I am for simplistic reasons going to call 'mypackage.go'.

In this file we are going to create an interface that will expose our public methods outside of this package.

type IPackage interface{
     Method1(string obj) error
     Method2(string obj) string
}

Now we need to create a struct to implement this interface

type Package struct {
}

Next we create the functions we are going to use, and make sure you use a pointer to the struct you have just crated.

func(p *Package)Method1(string obj) error {
        //add all the code needed here
}

func(p *Package)Method2(string obj) string {
        //add all the code needed here
}

Ok we have now created all we need to on our package, we can move onto implementing this in our code that is going to need testing, by mocking of this package.

In a new go file first thing we need to do is create a reference to the package. Create a var to the interface package

var package IPackage

Now instantiate the interface with the concrete struct.

package = new(Package)

Using this object you can access the functions we created.

err := package.Method1("hello")
string := package.Method2("world")

So far we have created a package with an interface for public methods, then used this package and the exposed methods in our code.

The next thing we require to do is test our code in our app, not in the package. To do this we require the ability to Mock the Methods in our package, giving set responses.

In the standard Go testing file import the stretchr/testify API.

Now we need to set up our mocking on the package and methods so when they are called in our app code we can control the response.

So lets create a mock object struct.

type MockPackage struct {
       mock.Mock
}

Next create a local var of our struct

var mockPackage *MockPackage

Next we set up the methods we want to mock. This only need to be done once for each method and just sets how it takes the arguments in and what it is set to return.

func(p *MockPackage)Method1(string obj) error {
       args := p.Mock.Called(obj)
       return args.Error(0)
}

func(p *MockPackage)Method2(string obj) string {
       args := p.Mock.Called(obj)
       return args.Get(0).(string)

Finally we get onto the fun bit. Using these mocked methods in our tests, setting the expected results, enabling us to test the areas that we really want to test in our code and not the package code.

lets create a test

func TestMethod(t *testing.T){

       mockPackage := new(MockPackage)
       package = mockPackage

       mockPackage.Mock.On("Method1", mock.Anything).Return(fmt.Errorf("mock error"))

       //now do your code here, if's, loops.....logic that need testing in your app.
       err := someMethodtoTest()

      //can use testify to assert variables.
      assert.NotNil(t, err, "should have found error")

       assert.Equal(t, true, mockPackage.Mock.AssertNumberofCalls(t, "Method1", 1), "Method1 not called the correct amount")

}

The first thing you need to do is 'override' the real object calls with the new Mock object. This is done by creating an instance of the Mock object and then setting the real object to it. This will make it so that every time the real object is called it will use your Mock methods instead.
The Mock methods are then each set up meaning that when in the code "Method1" is called and containing anything as its variable it will return an error. Then we call the code in our app that we want to test. Lets say our code we want to test is that when our Package Mehtod1 is called and returns an error, we want to bubble that error up to this method. Using the assert.NotNil method checks the error returned.

The second assert is very useful so I have given an example. It uses two asserts in one. First it does an Equals assert, then it uses a second assert to gain the count of the method called.

There are many more examples on their Git hub site and API documentation, this as explained more of a simple set up of your package and how to use in code and tests.

Hope this has helped. comments are always welcome. I will be uploading code snipping as soon as I can.