テストでしか使わないパッケージをgo.modに含めない方法

元エントリは↓で、これが全てです。

dev.to

Goでツールではなくライブラリ(パッケージ)を作っているとき、テストにしか使わないパッケージがgo.modに入って依存関係ができてしまうのが、いつも気になっていました。

ただ、「まあ別にいいかな」と思っていたのですが、ちょうど標準パッケージだけで機能が実現できるパッケージができたので、どうしてもgo.modを綺麗にしたくなりました。

そして、えいっと調べてみたらすぐに解決方法が見つかったのでした。

テストでしか使わないパッケージをgo.modに含めない方法

方法は次の通りです*1

  • テスト用に go_test.mod ファイルを用意して -modfile オプションを使って go_test.mod ファイルを指定して go test を実行する
  • (例えば)go.modの更新に go mod tidy を使わない

テスト用に go_test.mod ファイルを用意して -modfile オプションを使って go_test.mod ファイルを指定して go test を実行する

-modfile でgo.modを指定できるので(知らなかった!)、テスト用にgo_test.modファイルを指定するようにすることでパッケージとしての依存関係とテスト実行時の依存関係を別に管理します。

(例えば)go.modの更新に go mod tidy を使わない

公式の go mod tidy の説明によると

go mod tidy works by loading all of the packages in the main module and all of the packages they import, recursively.

とのことで、これにはテストコードも含まれます。

なので、 go mod tidy をそのまま使用することをやめるか、

Note that go mod tidy will not consider packages in the main module in directories named testdata or with names that start with . or _ unless those packages are explicitly imported by other packages.

とのことなので、テストコードを testdata ディレクトリ以下に押し込んでしまえば、テストでしか使わないパッケージが go.mod に入ることを回避できそうです。

ただ、 go mod tidy が使えないのは面倒...

具体的にどうしているか

https://github.com/k1LoW/rp/blob/aa26b46a7d17cdeb16370c1b704ee741c5e7b5b4/Makefile#L8-L10

$ cp go.mod testdata/go_test.mod
$ go mod tidy -modfile=testdata/go_test.mod
$ go test ./... -modfile=testdata/go_test.mod -coverprofile=coverage.out -covermode=count

のような感じで go_test.mod を生成してテストを実行しています。

もっといい方法がありそう

「私はこうやって解決しているよ」というのがあれば是非教えてください!

*1:エントリ公開当初「テストコードを別パッケージにする」と書いていましたが特に必要ありませんでした