How to Unit Test and Mock a Function in Go


Whenever you deliver your code, you must deliver it with quality.

Sharing is caring!

Introduction

During my professional experience, I usually written my code in Java. I have to admit Java ecosystems are mature enough. They provided lots of frameworks or libraries which are very useful and stable. One of the best frameworks which are very practical is their unit test framework. Assuming that you are a Java programmer, you have must heard JUnit or TestNG as a unit test tools.

Mocking

As you may notice, JUnit or TestNG itself sometimes are not enough to cover your test. Because one of the key aspect of unit testing is controlling your test environment. Let us assume that we need external dependency or third party APIs. We cannot rely on those APIs in order to make our test runs as expected. Because sometimes the latency is high or the service maybe not available. Next thing to happen is your test will fail and break the deployment.

One of the techniques to oversight this case is, by mocking the object or functionalities. That is why library such as Mockito are very handy to manage mocking objects. You can expect the behavior of your object as a simulation during the runtime.

Mocking in Go

Go itself already shipped with testing module. So we do not need to import another library just to execute the test. However, in my opinion, it does not suffice. It is good to execute standard testing. On the other hand, whenever you need to mock your functions/methods, you need an additional package.

I was searching several mocking package for Go, and there are two packages that I found interesting:

  1. HttpMock. This library is useful to simulate HTTP request to third party libraries.
  2. Testify. Useful for mocking functions/methods and provide assert functionality. The assert function is effective because we do not need to type t.Error()

Use Case

I want to see latest currency exchange rate on my application. I need exchange rate from six currencies, which are USD, CAD, AUD, IDR, NZD and SGD. Here is the requirement in the user story formula:

Story

As a user I want to see latest currency rates in order to exchange my current currency.

Acceptance Criteria

Given input USD then user will see rates from CAD, AUD, SGD, NZD and IDR

Step by Step

First of all, what I need is to get third party API for currency exchange. For this case, I choose fixer.io because it is free.

Notes: I will try to do this in TDD fashion.

Step 1: Define Request and Response

As usual, create structs to handle request and response.

Step 2: Define an Interface

Create an interface to get rates and another struct to implement the interface.

Step 3: Create a Unit Test for getRates Function

For this unit testing, I will use HttpMock functionality to simulate API request. Also there are three scenario to be aware of.

  1. Making request return 200 OK
  2. Making request return empty body
  3. Making request but invalid JSON.

Of course you can add another scenario. It depends on your requirements.

When you try to run first time, it will return error because we have done nothing in getRates function. So next step is to implement that function.

Now your test should be green or no error.

Step 4: Create Public Function to Get Current Rates

In this step, first we target the test file first. Three important points here, which are creates the mock struct and named it ratesMock. Then ratesMock implements functions in AccessRate interface. Then simulate the behavior by using mock.On(..).Return(..) functionalities.

Next implement the functions.

Step 5: Run it

If you are using Gogland IDE, it offers some cool features like coverage test. So here is the sample result:

test coverage

Advance: Behavior Driven Development (BDD)

Another testing technique is Behavior Driven Development (BDD). To support this technique there are third party library for Go. One of the library is Gucumber. This library inspired by Cucumber, which widely known in Java and Ruby ecosystem.

I will slightly highlight the BDD here. If you want to know about the details, you can visit their website.

We will create a feature file first based on our user story.

Then create a step definition for this feature.

Then execute it by typing

Conclusion

Go has already shipped with testing modules. By using its modules, we can create unit tests based on standard scenario. However, whenever we want to leverage our code coverage, it would become complicated because it does not provide the mocking object. That is why we need additional libraries such as httpmock and testify in order to make our testing environment controllable.

Maybe one side note, it would be nicer if testify provides a function which are similar to doThrow() in Mockito. Because at present, I found it is hard to simulate the runtime error.

That’s all from me. You can see whole sample on my repository. Thank you and cheerio!

Author: ru rocker

I am a professional software developer with more than 10 years experiences. I am a certified Java Developer (SCJP and SCWCD). However, In the recent months, I have more interest in DevOps and start to become a polyglot developer. Python and Go-lang become my favorite programming languages besides Java.

Leave a Reply

Your email address will not be published. Required fields are marked *