How I mock unit tests in Golang
Tags: go, testing, oop, programming
Published: 2021-03-17 23:46:25

>First of all I just want you guys to know that I'm not a golang expert, I started to use golang as a hobbyist a few months ago but now every web backend project I use it.

## System

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q2cp2y8ozwz1gro3on5m.png)

Note the arrow direction what means that Domain layer have no Idea about App layer so I promise I'll try to keep this in the code.

That's all ! Lets start as simple as possible to focus on tests it self and maybe further I can add more layers into this system and update this diagram but thats it for now.
## Domain Layer
`event.go`
```golang
package domain

import "time"

type Event struct {
	Title           string    
	Date            time.Time 
	Place           string        
	Category        string    
	KeyWords        []string  
}

type EventSaver interface {
	Save(Event) error
}
```

1. `Event` is the struct that represents an event in the system
2. `EventSaver` is the interface that will be implemented by someone who wants to save an event somehow, often called as an use case of the system.

## Use Cases Layer
For simplicity, I made just one use case named `AddEvent Memory ` that try to save the event and pass the error to who called it.
`event.go`
```golang
package usecases

import (
	"github.com/iamseki/dev-to/domain"
)

type AddInMemoryRepository interface {
	Add(domain.Event) error
}

type AddEventInMemory struct {
	repository AddInMemoryRepository
}

func (usecase *AddEventInMemory) Save(e domain.Event) error {
	err := usecase.repository.Add(e)
	return err
}

func NewAddEventInMemory(r AddInMemoryRepository) *AddEventInMemory {
	return &AddEventInMemory{repository: r}
}

```
## Testing
With the `testing` built in package we can easily start to write unit tests in _go_, so lets do it !

Lets focus on this peace of code:

```golang
type addEventFakeRepository struct {
	MockAddFn func(domain.Event) error
}

func (fake *addEventFakeRepository) Add(e domain.Event) error {
	return fake.MockAddFn(e)
}

func newAddEventFakeRepository() *addEventFakeRepository {
	return &addEventFakeRepository{
		MockAddFn: func(e domain.Event) error { return nil },
	}
}
```
1. `addEventFakeRepository` struct implements the `AddInMemoryRepository` interface due to implementation of Add method so we can inject it into _add event use case_
2. `MockAddFn` it's the function used to mock the implementation of `AddInMemoryRepository`
3. `newAddEventFakeRepository` creates an instance of `AddEventFakeRepository` then mocking the case of *success* returning error as a nil.

However if the case of success its not desirable, we can set the mock function as follow:
```golang
func TestAddEventInMemoryCustom(t *testing.T) {
	r := newAddEventFakeRepository()
	r.MockAddFn = func(e domain.Event) error { 
		// do something diferent here !
	}
	sut := usecases.NewAddEventInMemory(r)
}
```
Source code of all test in usecases package:
`event_test.go`
```golang
package usecases_test

import (
	"testing"

	"github.com/iamseki/dev-to/domain"
	"github.com/iamseki/dev-to/usecases"
)

type addEventFakeRepository struct {
	MockAddFn func(domain.Event) error
}

func (fake *addEventFakeRepository) Add(e domain.Event) error {
	return fake.MockAddFn(e)
}

func newAddEventFakeRepository() *addEventFakeRepository {
	return &addEventFakeRepository{
		MockAddFn: func(e domain.Event) error { return nil },
	}
}

func TestAddEventInMemorySucceed(t *testing.T) {
	r := newAddEventFakeRepository()
	sut := usecases.NewAddEventInMemory(r)

	err := sut.Save(domain.Event{})
	if err != nil {
		t.Error("Expect error to be nil but got:", err)
	}
}
```

---
### Considerations

I hope this can be useful for someone, I really enjoy to mock my tests in the way I describe here but I'm not pretty shure about how idiomatic it is so I open to suggestions !

:scroll: [source code](https://github.com/iamseki/dev-to/tree/how-i-mock-unit-tests)