9
7

More than 3 years have passed since last update.

gomock使っていてimport cycle not allowedになってしまったので self_package フラグで対応した

Posted at

はじめに

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.gorepositories.goを利用する構成。repositoriesはDBにあるデータとやり取りするためのインターフェースを持っています。

tagservice
├── domain.go
├── domain_test.go
└── repositories.go

やろうとして失敗したこと

自動生成されるモックのファイルを同じ階層に持つのが嫌だったので1階層下にtestmockディレクトリを作ろうとしました。

mockgenで生成
$ 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)で定義されている構造体を含んでいました。

testmock/repositories_mock.go
// 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.gotagserviceパッケージ内にあるためtagservice->testmock->tagserviceとなっています。

対応

選択肢としてdomain_test.gorepositories_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で生成できるようにしています。

domain_test.go
//go:generate mockgen -source=repositories.go -destination=repositories_mock.go -package=tagservice -self_package=github.com/momotaro98/mixlunch-service-api/tagservice
9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7