In this example we are going to test a function but by mocking it. Mocking is important because sometimes we don't want to run the real logic of a given function for any given reason.


Installation


Install mockery binary to OS with go get github.com/vektra/mockery/v2/.../ command first. This will also add relevant entries to go.mod/sum but you can remove them all because you will have to run go get -u http://github.com/stretchr/testify command which will be enough.


Example


package file

import (
"image"
"mime"
"os"

_ "image/gif"
_ "image/jpeg"
_ "image/png"
)

type Manager interface {
Mime(path string) (string, error)
}

type Image struct {}

func (Image) Mime(path string) (string, error) {
fil, err := os.Open(path)
if err != nil {
return "", err
}
defer fil.Close()

_, mim, err := image.DecodeConfig(fil)
if err != nil {
return "", err
}

return mime.TypeByExtension("." + mim), nil
}

Test


There is a Manager interface in ./internal/file/file.go file and we are creating its mock ./internal/file/mocks/manager.go file.


$ mockery --name Manager --dir ./internal/file/ --output ./internal/file/mocks --filename manager.go

22 Jul 20 10:21 BST INF Starting mockery dry-run=false version=(devel)
22 Jul 20 10:21 BST INF Walking dry-run=false version=(devel)
22 Jul 20 10:21 BST INF Generating mock dry-run=false interface=Manager qualified-name=github.com/you/client/internal/file version=(devel)

package file

import (
"fmt"
"testing"

"github.com/you/client/internal/file/mocks"

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

func TestFile_Mime(t *testing.T) {
mockFile := &mocks.Manager{}

t.Run("file not found error", func(t *testing.T) {
mockFile.
On("Mime", "some-file.png").
Once().
Return("", fmt.Errorf("file not found"))

mim, err := mockFile.Mime("some-file.png")

assert.Empty(t, mim)
assert.Error(t, err, "file not found")
})

t.Run("config decoding error", func(t *testing.T) {
mockFile.
On("Mime", "some-file.png").
Once().
Return("", fmt.Errorf("config error"))

mim, err := mockFile.Mime("some-file.png")

assert.Empty(t, mim)
assert.Error(t, err, "config error")
})

t.Run("successfully getting mime", func(t *testing.T) {
mockFile.
On("Mime", "some-file.png").
Once().
Return("image/png", nil)

mim, err := mockFile.Mime("some-file.png")

assert.Equal(t, "image/png", mim)
assert.NoError(t, err)
})
}

$ go test -v -run TestFile_Mime ./internal/file/

=== RUN TestFile_Mime
=== RUN TestFile_Mime/file_not_found_error
=== RUN TestFile_Mime/config_decoding_error
=== RUN TestFile_Mime/successfully_getting_mime
--- PASS: TestFile_Mime (0.00s)
--- PASS: TestFile_Mime/file_not_found_error (0.00s)
--- PASS: TestFile_Mime/config_decoding_error (0.00s)
--- PASS: TestFile_Mime/successfully_getting_mime (0.00s)
PASS