Creating test mocks using GoMock
Tags: go, mocks, tests
Published: 2019-12-20 17:35:52

---
title: Creating test mocks using GoMock
published: true
description: 
tags: go, mocks, tests
---
Using [mocks](https://en.wikipedia.org/wiki/Object_Mock) in test development is a concept used in the vast majority of programming languages. In this post, I will talk about one solution to implement mocks in Go: [GoMock](https://github.com/golang/mock). 

To show GoMock functionality, I will use the tests created in my [repository](https://github.com/eminetto/clean-architecture-go) about [Clean Architecture](https://eltonminetto.dev/en/post/2018-03-05-clean-architecture-using-go/) 

Clean Architecture encourages testing across all layers, so it’s easy to see where we can use mocks to make development easier. As we write [unit tests for the *UseCases* layer](https://github.com/eminetto/clean-architecture-go/blob/master/pkg/bookmark/service_test.go) we are sure that the logic in this layer is covered by testing. In the *Controller* layer, we can use mocks to simulate the use of *UseCases* since we know that their functionality is already validated. 

Let's create mocks for this layer, which is represented by the [interfaces](https://github.com/eminetto/clean-architecture-go/blob/master/pkg/bookmark/interface.go):

```go
package bookmark

import "github.com/eminetto/clean-architecture-go/pkg/entity"

//Reader interface
type Reader interface {
	Find(id entity.ID) (*entity.Bookmark, error)
	Search(query string) ([]*entity.Bookmark, error)
	FindAll() ([]*entity.Bookmark, error)
}

//Writer bookmark writer
type Writer interface {
	Store(b *entity.Bookmark) (entity.ID, error)
	Delete(id entity.ID) error
}

//Repository repository interface
type Repository interface {
	Reader
	Writer
}

//UseCase use case interface
type UseCase interface {
	Reader
	Writer
}
``` 

To make GoMock easier to use let's change the [*Makefile* file](https://github.com/eminetto/clean-architecture-go/blob/master/Makefile) to add mock generation functionality from the interfaces::

```bash
build-mocks:
  @go get github.com/golang/mock/gomock
  @go install github.com/golang/mock/mockgen
  @~/go/bin/mockgen -source=pkg/bookmark/interface.go -destination=pkg/bookmark/mock/bookmark.go -package=mock
```

These commands download the *gomock* package and also the *mockgen* binary, which is used to generate the mocks. The command **make build-mocks** will generate the file *pkg/bookmark/mock/bookmark.go*, with the functions we will use in the tests. It is important to remember that whenever you change the interfaces of the *pkg/bookmark/interface.go* file, you have to run this command to update the mocks. 

Let's now change one of the existing tests to make use of the mock. In the file *api/handler/bookmark_test.go* we will change the test *TestBookmarkIndex*. The original code was:

```go
func TestBookmarkIndex(t *testing.T) {
  repo := bookmark.NewInmemRepository()
  service := bookmark.NewService(repo)
  r := mux.NewRouter()
  n := negroni.New()
  MakeBookmarkHandlers(r, *n, service)
  path, err := r.GetRoute("bookmarkIndex").GetPathTemplate()
  assert.Nil(t, err)
  assert.Equal(t, "/v1/bookmark", path)
  b := &entity.Bookmark{
    Name:        "Elton Minetto",
    Description: "Minetto's page",
    Link:        "http://www.eltonminetto.net",
    Tags:        []string{"golang", "php", "linux", "mac"},
    Favorite:    true,
  }
  _, _ = service.Store(b)
  ts := httptest.NewServer(bookmarkIndex(service))
  defer ts.Close()
  res, err := http.Get(ts.URL)
  assert.Nil(t, err)
  assert.Equal(t, http.StatusOK, res.StatusCode)
}
```

And the new code is:

```go
func TestBookmarkIndex(t *testing.T) {
  controller := gomock.NewController(t)
  defer controller.Finish()
  service := mock.NewMockUseCase(controller)
  r := mux.NewRouter()
  n := negroni.New()
  MakeBookmarkHandlers(r, *n, service)
  path, err := r.GetRoute("bookmarkIndex").GetPathTemplate()
  assert.Nil(t, err)
  assert.Equal(t, "/v1/bookmark", path)
  b := &entity.Bookmark{
    Name:        "Elton Minetto",
    Description: "Minetto's page",
    Link:        "http://www.eltonminetto.net",
    Tags:        []string{"golang", "php", "linux", "mac"},
    Favorite:    true,
  }
  service.EXPECT().
    FindAll().
    Return([]*entity.Bookmark{b}, nil)
  ts := httptest.NewServer(bookmarkIndex(service))
  defer ts.Close()
  res, err := http.Get(ts.URL)
  assert.Nil(t, err)
  assert.Equal(t, http.StatusOK, res.StatusCode)
}
```

The changes were in the service creation, where we are now using the mock:

```go
controller := gomock.NewController(t)
defer controller.Finish()
service := mock.NewMockUseCase(controller)
```

We removed the line **_, _ = service.Store(b)** because we no longer need to include a record before using it. And we include the mock setup:

```go
service.EXPECT().
  FindAll().
  Return([]*entity.Bookmark{b}, nil)
```

This way the mock will behave as expected. So we can focus on testing only what interests us in this layer, which is the logic of the http handler such as handling of request and response, routes. 

Also, we need to import the packages:

```go
"github.com/eminetto/clean-architecture-go/pkg/bookmark/mock"
"github.com/golang/mock/gomock"
```

In the repository you can see the [other tests](https://github.com/eminetto/clean-architecture-go/blob/master/api/handler/bookmark_test.go). 

Using mock is not a consensus in the development community, with some people supporting and others pointing out problems in some approaches. I have been using this technique lately and enjoying the result as it helps keep the tests more focused. This can avoid re-testing things that have already validated with unit tests in other layers. It is also useful when we need to emulate code access to an external micro service, library, or resource. 

Since all standard Go libraries extensively use interfaces, you can create mocks for many resources such as files, databases. That’s why I believe that solutions like GoMock can be very useful in projects of various sizes.