Golang “Mocking” a Function for Unit Testing

Credits to Tamara Gak (https://unsplash.com/photos/1vZAezBEADw)

Continuing our basic Golang unit testing example, we are going to continue on another step of simple function mocking for unit testing in Go. In here We’re only going cover this two “kind” of function:

  1. Function in your own package
  2. Function imported (from library or stuff) outside of your project

Therefore, we’re not going to “mock” method which belongs to a struct right now. You might ask, why do I need to mock a function? Can we just call the function as is? The simple answer is, if your function contains API / DB call (external call), you should mock it in your test environment.

So Let’s Get Started

Let say you have a function like this

type Person struct { ID       int    `db:"id" json:"id"` Name     string `db:"name" json:"name"` BornDate string `db:"born_date" json:"born_date"`}type Address struct { ID         int    `db:"id" json:"id"` UserID     int    `db:"user_id" json:"user_id"` Street     string `db:"street" json:"street"` PostalCode string `db:"postal_code" json:"postal_code"`}type UserProfile struct { User    Person  `json:"person"` Address Address `json:"address"`}func GetPersonByID(id int) (*Person, error) { var user Person err := db.Get(&user, `SELECT id, name, born_date FROM users WHERE id = ?`, id) if err != nil {  return nil, err } return &user, err}func GetPersonAddrByUserID(userID int) (*Address, error) { var addr Address err := db.Get(&addr, `SELECT id, user_id, street, postal_code FROM address WHERE user_id = ?`, userID) if err != nil {  return nil, err } return &addr, err}func GetUserProfile(userID int) (UserProfile, error) { var userProfile UserProfile p, err := GetPersonByID(userID) if err != nil {  return userProfile, err } a, err := GetPersonAddrByUserID(userID) if err != nil {  return userProfile, err } userProfile.User = *p userProfile.Address = *a return userProfile, nil}func JSONMarshalUserProfile(up UserProfile) ([]byte, error) { return json.Marshal(up)}

Then you want to test these two functions (since they depends on function that connect to DB / external lib) and you want them not to do that in test environment (if you want to control what the function returning):

  1. GetUserProfile
  2. JSONMarshalUserProfile

We’re not going to cover the mocking DB function for this writing, therefore GetUserByID and GetPersonAddress database mocking won’t be covered right now.

Do you know you can put your function as a variable? Therefore we can create the function like these (simplified)

var GetPersonByID = func(id int) (*Person, error) {
var user Person
.... // function content
var GetPersonAddrByUserID = func(userID int) (*Address, error) {
var addr Address
... // function content

After modifying the function, we can mock / override your function implementation like this.

GetPersonByID = func(id int) (*Person, error) {

So When you’re writing the unit test, you can put it all like these.

Inside the mockFunc, we will mock both functions (GetPersonByID and GetPersonAddrByUserID) to just return a constant value depends on our test case. Take a note that we need to save the original function so we can revert the function (variable) back to its original implementation after the unit test is done (line 96,97,115,116).

Function From External

So what about function from a library / another project packages? For example, let say we have this function

func JSONMarshalUserProfile(up UserProfile) ([]byte, error) {  return json.Marshal(up)}

We’re going to do the same approach but a little bit different. We can save the json.Marshal to a variable, ie like this:

var marshalJSON = json.Marshal
func JSONMarshalUserProfile(up UserProfile) ([]byte, error) { return marshalJSON(up)}

If you want to test JSONMarshalUserProfile, you can easily mock the marshalJSON function like the previous method since it’s just a variable which you can override.

marshalJSON = func(v interface{}) ([]byte, error) {     // Put your mocking / testing implementation here

As you can see, it also works for external package, i know some of you might think that this is not clean for some reason, like too many global variables of function (if you’re using the methods for a lot of external function). We’re going to cover that in the future discussion about leveraging an interface for cleaner mocking.

Hope this useful for you, see ya :)




Fellow Software Engineer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Cloud computing

Python Applications 2020: Features, Advantages, Types, Scope

KESS KTAG V2 ECM Master Version Online Titanium Programmer

How I turned my DK Bongos Into a Keyboard

J. A. Cirez ♥ Flutter + Canonical

J. A. Cirez ♥ Flutter + Canonical

Customer-Focused Collaboration

503 Back-end server is at capacity

Dictionary In Details: Python Programming

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Aditya Rama

Aditya Rama

Fellow Software Engineer

More from Medium

Testing the main of a golang http server

Testing in Golang(Part 1)— Unit Tests

Mocking HTTP Call in Golang a Better Way

Photo by @jim_reardan on Unsplash

gorilla/mux 101 (rk-boot): Error handling