はじめに
gomockを使ってテストモックを管理する際、self_package というフラグを使うことになりました。このフラグに関して利用方法が書いてある記事がネット上に少なかったので書きます。
Version
$ go version
go version go1.13.1 darwin/amd64
$ cat go.mod | grep mock
github.com/golang/mock v1.3.1
構成
domain.go
がrepositories.go
を利用する構成。repositoriesはDBにあるデータとやり取りするためのインターフェースを持っています。
tagservice
├── domain.go
├── domain_test.go
└── repositories.go
やろうとして失敗したこと
自動生成されるモックのファイルを同じ階層に持つのが嫌だったので1階層下にtestmockディレクトリを作ろうとしました。
$ mockgen -source=repositories.go -destination=./testmock/repositories_mock.go -package=testmock
上記を実行すると以下のようにtestmock/repositories_mock.go
が作られました。
tagservice
├── domain.go
├── domain_test.go
├── repositories.go
└── testmock
└── repositories_mock.go
生成されたモックを元にテストを書いた後、テストを実行してみます。
$ go test
# github.com/momotaro98/mixlunch-service-api/tagservice
import cycle not allowed in test
package github.com/momotaro98/mixlunch-service-api/tagservice (test)
imports github.com/momotaro98/mixlunch-service-api/tagservice/testmock
imports github.com/momotaro98/mixlunch-service-api/tagservice
FAIL github.com/momotaro98/mixlunch-service-api/tagservice [setup failed]
import cycle not allowed in test
と出て失敗してしまいました。
なぜ循環参照になっているかを確認すると生成されたモックのメソッドのシグネチャ内に対象パッケージ(tagservice)で定義されている構造体を含んでいました。
// Code generated by MockGen. DO NOT EDIT.
// Source: repositories.go
// Package testmock is a generated GoMock package.
package testmock
import (
gomock "github.com/golang/mock/gomock"
tagservice "github.com/momotaro98/mixlunch-service-api/tagservice" // 元のパッケージが必要
reflect "reflect"
)
/// 中略
func (m *MockITagQueryRepository) QueryTagsWhereTagType(tagTypeId uint8) ([]*tagservice.TagQueryDto, error) {
domain_test.go
がtagservice
パッケージ内にあるためtagservice->testmock->tagserviceとなっています。
対応
選択肢としてdomain_test.go
をrepositories_mock.go
と同じ1個下の階層に入れて外部パッケージとしてテストするやり方もありますが、現状都合から難しかったので、生成されるモックファイルをtagserviceパッケージに入れることにしました。
https://github.com/golang/mock/issues/230#issuecomment-446744057 のIssueで-self_package
フラグがmogckgen
にあることがわかりました。
-self_package string (著者日本語訳)
生成されるコードが置かれるパッケージimportの絶対パス。 このフラグの目的は、(インターフェースがある)元のパッケージを含めることにより、生成されたコードのインポートサイクルを防ぐことです。 mockgenにてモックのパッケージが入力に設定され、出力がstdioであるため、mockgenは最終出力パッケージを検出できません。 このフラグを設定すると、mockgenが生成するモックファイルにて除外するパッケージimportを指定できます。
self_package フラグを使ってモックを生成
$ mockgen -self_package=github.com/momotaro98/mixlunch-service-api/tagservice -source=repositories.go -destination=repositories_mock.go -package=tagservice
以下のようになりテストが通るようになりました。
tagservice
├── domain.go
├── domain_test.go
├── repositories.go
└── repositories_mock.go
ちなみに
mockgenのコマンドは//go:generate
でコード内に記載してgo generate
で生成できるようにしています。
//go:generate mockgen -source=repositories.go -destination=repositories_mock.go -package=tagservice -self_package=github.com/momotaro98/mixlunch-service-api/tagservice