skip to content
Alvin Lucillo

Simple use case of mockery

/ 2 min read

Yesterday, we saw how an interface is generated. Now, let’s put it to use. We want to test Validate, which is a function that injects the service. TestValidate is the test case that instantiates the mocked service NewService to set an expectation. It is important that the actual number of arguments match the expectation, both the receiving and returning. The returning arguments are the actual values received by the caller. In the test case, we want to receive an empty first argument, which in turn makes Validate function return ErrEmptyRows. This is a simple example of how we can make use of mocks for unit test. We mock the dependencies so we can focus on testing the function.

Unit test:

func TestValidate(t *testing.T) {

	svc := NewService(t)
	svc.On("GetRows", mock.Anything).Return(nil, nil)

	err := Validate(context.Background(), svc)
	require.ErrorIs(t, err, ErrEmptyRows)
}

Function to test:

var ErrEmptyRows = errors.New("empty rows")

func Validate(ctx context.Context, service models.Service) error {

	rows, err := service.GetRows(ctx)
	if err != nil {
		return err
	}

	if len(rows) == 0 {
		return ErrEmptyRows
	}

	return nil
}

Service mock:

// Code generated by mockery v2.53.5. DO NOT EDIT.

package servicemock

import (
	context "context"

	mock "github.com/stretchr/testify/mock"
)

// Service is an autogenerated mock type for the Service type
type Service struct {
	mock.Mock
}

// GetRows provides a mock function with given fields: ctx
func (_m *Service) GetRows(ctx context.Context) ([]interface{}, error) {
	ret := _m.Called(ctx)

	if len(ret) == 0 {
		panic("no return value specified for GetRows")
	}

	var r0 []interface{}
	var r1 error
	if rf, ok := ret.Get(0).(func(context.Context) ([]interface{}, error)); ok {
		return rf(ctx)
	}
	if rf, ok := ret.Get(0).(func(context.Context) []interface{}); ok {
		r0 = rf(ctx)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]interface{})
		}
	}

	if rf, ok := ret.Get(1).(func(context.Context) error); ok {
		r1 = rf(ctx)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewService(t interface {
	mock.TestingT
	Cleanup(func())
}) *Service {
	mock := &Service{}
	mock.Mock.Test(t)

	t.Cleanup(func() { mock.AssertExpectations(t) })

	return mock
}