Golang: How to mock test

Hello folks, though we are passing a critical time due to the COVID-19 pandemic I hope you all are well and safe.

In software development one of the major & critical parts is software testing. Testing can vary in type. Today you will learn how you can implement mock testing in your Golang project.

What is the mock test?

Mock testing is an approach to unit testing that lets you make assertions about how the code under test is interacting with other system modules. In mock testing, the dependencies are replaced with objects that simulate the behaviour of the real ones. Mainly in mock testing, we simulate the behaviour of a third-party service, we are using in our project.

How to mock?

In this project, I will use https://github.com/golang/mock library to implement mock testing. If you want you can use any other library as well. Now create a project and execute the following to include the libraries in your project,

go get github.com/golang/mock/gomock
go get github.com/golang/mock/mockgen
go get github.com/stretchr/testify

github.com/stretchr/testify is a test assertion library.

Let's say we have two micro-services mockingjay and user . In mockingjay we have integration with user service, so we will simulate the behaviour the of user service in mockingjay service.

Let's have an interface defining the behaviour of user service.

type UserService interface {
	CreateUser(name, email string) (*User, error)
	UpdateUser(ID, name, email string) (*User, error)
	GetUser(ID string) (*User, error)
	DeleteUser(ID string) error
}

In above interface we have defined the CRUD operations of user service.

type User struct {
	ID    string
	Name  string
	Email string
}

Now the below code will generate mocks based on these definitions,

//go:generate mockgen -source=user_service.go -destination mocks/mock_user_service.go -package mocks UserService

Below is the project structure,

Now execute the below command to generate mocks,

go generate ./...

Then you will have mock_user_service.go generated with the mocks.

In this step, we will implement the test using Golang 's testing feature.

func Test_UserService_CreateUser(t *testing.T) {
	
}

With the above function, we will mock CreateUser function,
To do that we have to add gomock Controller ,

func Test_UserService_CreateUser(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

}

Okay, we have the basic structure. Now we will add user service mocking,

func Test_UserService_CreateUser(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	expectedID := "1"
	expectedName := "Sakib"
	expectedEmail := "[email protected]"
	expectedUser := &User{ID: expectedID, Name: expectedName, Email: expectedEmail}

	mockUserService := mocks.NewMockUserService(ctrl)
	mockUserService.EXPECT().CreateUser(expectedName, expectedEmail).Return(expectedUser, nil).Times(1)

}

With the above, we have defined that the CreateUser function will be called with those parameters and it will return User and error nil .

Note that, with EXPECT function we are setting that we expect those parameters and results from that specific function. We can also define how many times the function will be called by Times function. You can check library documentation to learn more about it.

Now finally we will call CreateUser function.

func Test_UserService_CreateUser(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	expectedID := "1"
	expectedName := "Sakib"
	expectedEmail := "[email protected]"
	expectedUser := &services.User{ID: expectedID, Name: expectedName, Email: expectedEmail}

	mockUserService := NewMockUserService(ctrl)
	mockUserService.EXPECT().CreateUser(expectedName, expectedEmail).Return(expectedUser, nil).Times(1)

	u, err := mockUserService.CreateUser(expectedName, expectedEmail)
	require.NoError(t, err)

	require.Equal(t, expectedUser.ID, u.ID)
	require.Equal(t, expectedUser.Name, u.Name)
	require.Equal(t, expectedUser.Email, u.Email)
}

Run tests by executing, go test ./...

If the test fails, it will show output like this,

Now following the same, try to implement test for other functions.

Good luck. 🤞

Source code: https://github.com/s4kibs4mi/mockingjay