Bu örnekte bir fonksiyonu test edeceğiz ama onun sahte halini (mock) kullanarak. Mock önemlidir çünkü bazen belirli bir nedenden dolayı belirli bir işlevin gerçek mantığını çalıştırmak istemeyiz.


Kurulum


go get github.com/vektra/mockery/v2/.../ komutunu kullanarak mockery dosyasını OS içine yükleyin. Bu komut ayrıca go.mod/sum dosyalarına kendisi ile alakalı girdiler ekler ama siz bunları kaldırabilirsiniz çünkü go get -u http://github.com/stretchr/testify komutunu çalıştırmak yeterli olacaktır.


Örnek


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


./internal/file/file.go dosyasında Manager interface var ve biz bunun mock hali olan ./internal/file/mocks/manager.go dosyasını yaratıyoruz.


$ 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

Güncelleme


Mac'te Homebrew ile mockery'yi yükleyebilirsiniz. Ayrıca, artık koddaki arayüzlere mockery ile ilgili komutları eklemeniz gerekmiyor. Tüm komut bayraklarını görmek için mockery --help komutunu çalıştırabilirsiniz, ancak aşağıdakiler en çok kullanılanlardır.


--keeptree: Matches the actual package structure for the mock files
--inpackage: Uses the package name rather than "mocks"
--exported: Creates exported versions of unexported interfaces
--all: Creates mocks for all interfaces in all sub directories
--case=snake: Uses snake case for the file names

-- In root
- Runs through all interfaces in the codebase and puts mocks in root level "mocks" folder.
$ mockery --keeptree --inpackage --exported --all --case=snake

-- In package (classic)
- Runs through all interfaces in a package folder and puts mocks in "mocks" folder of same package folder.
$ mockery --exported --all --case=snake --dir=payment/ --output=payment/mocks

If you prefer running a common command $ go generate ./... to generate all mocks in one-go, you can try version below.


//go:generate mockery --exported --case snake --name Doer
type interface Doer {
...