Writing unit tests in Golang Part 2: Mocking

Siraphob K.
Nerd For Tech
Published in
4 min readSep 13, 2021

--

If you haven’t read Part 1 of this series, please don’t forget to check it out.

In software development, a program usually consists of many layers and functions which means multiple chunks of code have to be working together. Thus, it causes a lot of pain for programmers to create such a test to check that all parts are working properly. It will be a lot nicer to test each chunk of code individually. This is because it is easier to detect bugs or develop features when working with less code. And if all chunks of codes are working, the whole program is working.

We’ve learnt that unit testing is a kind of test that validates each smallest part of a program. You may ask … “ What if, my code (or my function) interacts with other modules? Something like databases, web servers, etc. Do I actually have to connect or transmit data to those modules when writing tests? ”

The answer is: no and I encourage you not to do so.

The next question is “ How to do it then? How do I test my code that interacts with other modules without actually doing it? ”.

The answer is: you can mock your code where it interacts with other modules. Mocking is a way of creating a stub (a fake, a not the real, you name it) piece of code that substitutes some functions of the whole code. Its purpose is to make testing easier because you can control those stub functions’ inputs and outputs freely which allows you to focus only on the business logic.

Example

The idea

I’m creating a computer with a printer as its component. The computer will have a function called PrintA4 which prints whatever content we provide in an A4 paper. The printer will also have its own function called Print which will print whatever content and paper size we provide.

The code

The following code is a demonstration of an application that will be used as a mocking example. There’s a Computer struct that has Pr as its field. The Pr field implements Printer interface. The Printer interface has a method Print . Also, MyPrinter is a struct that has a method Print . You can see that MyPrinter implements interface Printer . The Computer struct has a method PrintA4 .

Code for mocking demonstration

Now, we want to test the function PrintA4 which calls Pr.Print (Line12). The printer in this code is like “other module” we’ve discussed earlier. In order to test PrintA4 , we don’t actually have to print it from the printer. Therefore, we will create a stub function that mocks the function Print of the Printer interface. The test code is shown below.

Test code for mocking demonstration

Another main feature of testify is mocking. Testify offers you a mock package that you could create your own mock object to test your code.

On Line 10~21, I have created a mock object. This object will mock the Printer interface. On Line 30, you can see that the mock object calls the method On . This method sets expectations of the given mocked function. As in the example, I’ve set an expectation that the function Print will receive 2 arguments which are "A4" and "hello world" . After that, it calls Return to tell the mock object to reutrn nil as its return value.

On Line 37, when PrintA4 is called, it will call Pr.Print . On production, it should call Print of the object MyPrinter but in this case, it will call Print of the PrinterMock object instead. This is so great because we don’t actually have to call the real function. We don’t have to interact with other modules but only our stub functions. This makes the code testable and easier to debug.

Finally, we assert our expectation with AssertExpectations function. This function validates that the input of the stub function is correct and the stub function is properly called.

Generating Mocks using Mockery

One question comes to your mind “What if… what if my function has a lot of objects? And what if there’re many function calls of different objects inside my function, would I have to write all those mocks?”

The answer is: well yes but actually no.

Mockery is a very handy package that generates mocks for you. This way you won’t ever have to write mocks yourself because there’s an automation that handles such a job for you.

To use mockery, you can simply just type
go get github.com/vektra/mockery/v2/.../
and then go rungithub.com/vektra/mockery/v2 --all .

The mocks will be auto-generated for you into mocks folder. The example generated code from the Printer interface is shown below.

Example of generated code

And that’s it for part two. In the next part, I will be talking about test suite which is the last topic we will discuss. And for now, stay tuned and happy coding!

References

How I mock unit tests in Golang by Christian Seki
Mocking Techniques for Go by Kyle Yost

Read my other articles

--

--