Skip to main content

mock工具介紹

這次我們使用的是mock這個工具幫我們快速的模擬需要的interface

值得一提的是,因為這次要撰寫文章特別又回去看了文件,才發先原先golang提供的mock的github被archive了,現在是由uber來接管這個專案,所以如果未來大家要使用,要特別注意,不要用到archive的連結了 舊的: https://github.com/golang/mock 新的: https://github.com/uber-go/mock

要使用這個工具,要先瞭解他的原理 他的主要邏輯是,他可以針對你目前的interface透過工具的幫忙,自動產生出可以implement相對應的資料的內容 比如說,我先宣告了一個FileStorer的interface

package application

type FileStorer interface {
UploadAsset(filename string, i []byte, s string) (file domain.CloudFile, err error)
GetPreviewLink(asset domain.CloudFile) (link string, err error)
}

接著透過mock工具提供的cli

打上

mockgen -destination=file_store_mock.go -package=application -self_package=2023_asset_management/application . FileStorer

透過這個指令,他就可以幫你產生相對應的檔案

// Code generated by MockGen. DO NOT EDIT.
// Source: 2023_asset_management/application (interfaces: FileStorer)

// Package application is a generated GoMock package.
package application

import (
domain "2023_asset_management/domain"
reflect "reflect"

gomock "go.uber.org/mock/gomock"
)

// MockFileStorer is a mock of FileStorer interface.
type MockFileStorer struct {
ctrl *gomock.Controller
recorder *MockFileStorerMockRecorder
}

// MockFileStorerMockRecorder is the mock recorder for MockFileStorer.
type MockFileStorerMockRecorder struct {
mock *MockFileStorer
}

// NewMockFileStorer creates a new mock instance.
func NewMockFileStorer(ctrl *gomock.Controller) *MockFileStorer {
mock := &MockFileStorer{ctrl: ctrl}
mock.recorder = &MockFileStorerMockRecorder{mock}
return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockFileStorer) EXPECT() *MockFileStorerMockRecorder {
return m.recorder
}

// GetPreviewLink mocks base method.
func (m *MockFileStorer) GetPreviewLink(arg0 domain.CloudFile) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPreviewLink", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// GetPreviewLink indicates an expected call of GetPreviewLink.
func (mr *MockFileStorerMockRecorder) GetPreviewLink(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPreviewLink", reflect.TypeOf((*MockFileStorer)(nil).GetPreviewLink), arg0)
}

// UploadAsset mocks base method.
func (m *MockFileStorer) UploadAsset(arg0 string, arg1 []byte, arg2 string) (domain.CloudFile, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UploadAsset", arg0, arg1, arg2)
ret0, _ := ret[0].(domain.CloudFile)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// UploadAsset indicates an expected call of UploadAsset.
func (mr *MockFileStorerMockRecorder) UploadAsset(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadAsset", reflect.TypeOf((*MockFileStorer)(nil).UploadAsset), arg0, arg1, arg2)
}

他可以自動產生一個implement你指定interface的struct,並提供你在測試的時候需要的功能

當然,因為在每個interface下你都會需要這段工具,所以這時候就要使用go提供的一個工具 generate

當你在程式碼中放上這樣的一段內容

//go:generate mockgen -destination=file_store_mock.go -package=application -self_package=2023_asset_management/application . FileStorer
type FileStorer interface {
UploadAsset(filename string, i []byte, s string) (file domain.CloudFile, err error)
GetPreviewLink(asset domain.CloudFile) (link string, err error)
}

並且透過shell來執行以下指令

go generate ./filestore.go

如此一來,他就會去掃描你指定的這個檔案有沒有使用go:generate這個tag,並且執行後面所撰寫的程式碼內容

如此一來,就算之後有大量的interface需要產生mock file,也可以透過go generate來幫忙快速產生

更棒的是,go generate還有提供另一個方式,可以讓你可以你當前目錄下的所有檔案 方法如下

go generate ./...

如此一來,你只要整個專案都有放上go:generate的內容,都會被順利執行,相當的方便