gomockでGoのインターフェースのmockを作成してテストを実行する
今回はGoのmockフレームワークであるgomockの使い方を紹介したいと思います。
gomockとは、Go言語用のmockフレームワークで、組み込みのテストパッケージと合わせて利用するライブラリです。
インストール方法
$ go get github.com/golang/mock/gomock
go: finding github.com/golang/mock v1.4.4
go: downloading github.com/golang/mock v1.4.4
$ go get github.com/golang/mock/mockgen
go: downloading golang.org/x/tools v0.0.0-20190425150028-36563e24a262
go: extracting golang.org/x/tools v0.0.0-20190425150028-36563e24a262
go: finding golang.org/x/tools v0.0.0-20190425150028-36563e24a262
$ mockgen -version
v1.4.4
テスト対象のサンプルコード
package main
type ApiClient interface {
Request(string) (string, error)
}
type DataRegister struct {
client ApiClient // インターフェイスに依存しているだけで実装は存在しない
}
func (d *DataRegister) Register(data string) (string,error) {
result, err := d.client.Request(data)
if err != nil {
return "", err
}
return result, nil
}
gomockを使わないで自分でmockを用意した場合のテスト例
package main
import "testing"
// mockを自作する
type ApiClientMock struct {}
func (a *ApiClientMock) Request(data string) (string,error) {
return data, nil
}
func TestSample(t *testing.T) {
d := &DataRegister{}
d.client = &ApiClientMock{} // mockを登録
expected := "bar"
res, err := d.Register(expected)
if err != nil {
t.Fatal("Register error!", err)
}
if res != expected {
t.Fatal("Value does not match.")
}
}
テストの実行
$ go test -v -run TestSample
=== RUN TestSample
--- PASS: TestSample (0.00s)
PASS
ok example.com/go-mock-sample 0.001s
gomockを使った場合のテスト例
mockの生成
まずmockファイルを配置するためにmockディレクトリを作成します。
$ mkdir mock
次に対象ファイルを-sourceに指定し、作成したmockの出力先を-destinationに指定してmockgenコマンドを実行します。
$ mockgen -source=sample.go -destination mock/mock_sample.go
すると以下のようなmockファイルが生成されます。
// Code generated by MockGen. DO NOT EDIT.
// Source: sample.go
// Package mock_main is a generated GoMock package.
package main
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockApiClient is a mock of ApiClient interface
type MockApiClient struct {
ctrl *gomock.Controller
recorder *MockApiClientMockRecorder
}
// MockApiClientMockRecorder is the mock recorder for MockApiClient
type MockApiClientMockRecorder struct {
mock *MockApiClient
}
// NewMockApiClient creates a new mock instance
func NewMockApiClient(ctrl *gomock.Controller) *MockApiClient {
mock := &MockApiClient{ctrl: ctrl}
mock.recorder = &MockApiClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockApiClient) EXPECT() *MockApiClientMockRecorder {
return m.recorder
}
// Request mocks base method
func (m *MockApiClient) Request(arg0 string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Request", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Request indicates an expected call of Request
func (mr *MockApiClientMockRecorder) Request(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Request", reflect.TypeOf((*MockApiClient)(nil).Request), arg0)
}
MockApiClient構造体ががApiClientインターフェイスを実装しているのがわかります。
mockを使ったテストの実装
package main
import (
"testing"
"github.com/golang/mock/gomock"
mock_main "example.com/go-mock-sample/mock"
)
func TestSample(t *testing.T) {
// mockのコントローラを作成します
ctrl := gomock.NewController(t)
defer ctrl.Finish()
// ApiClientインターフェイスのmockを作成します
mockApiClinet := mock_main.NewMockApiClient(ctrl)
// 作成したmockに対して期待する呼び出しと返り値を定義します
// EXPECT()では呼び出されたかどうか
// Request()ではそのメソッド名が指定した引数で呼び出されたかどうか
// Return()では返り値を指定します
mockApiClinet.EXPECT().Request("bar").Return("bar", nil)
d := &DataRegister{}
d.client = mockCpiClinet // mockを登録
expected := "bar"
res, err := d.Register(expected)
if err != nil {
t.Fatal("Register error!", err)
}
if res != expected {
t.Fatal("Value does not match.")
}
}
テストの実行
$ go test -v -run TestSample
=== RUN TestSample
--- PASS: TestSample (0.00s)
PASS
ok example.com/go-mock-sample 0.002s
上記のテストケースでRequestメソッドをコールしなかったり、引数が”bar”でなかった場合にエラーを発生させてくれます。
まとめ
gomockの基本的な使い方をご紹介しました。 今回のような簡単なケースではあまり効果を実感しづらいと思いますが、 大量のテストケースがある場合や複雑なmockを作成する必要がある場合などには便利かと思います。
gomockにはまだまだ便利なメソッドが用意されているので公式のドキュメントを確認してみてください。
また、都度mockファイルを生成するのが面倒な場合はgo generateを使った方法などが紹介されています。
この記事を書いた人
- 創造性を最大限に発揮するとともに、インターネットに代表されるITを活用し、みんなの生活が便利で、豊かで、楽しいものになるようなサービスやコンテンツを考え、創り出し提供しています。
この執筆者の最新記事
RECOMMENDED
関連記事
NEW POSTS
最新記事
FOLLOW US
最新の情報をお届けします
- facebookでフォロー
- Twitterでフォロー
- Feedlyでフォロー