🙄

Go言語でテストケースからだけ呼び出しされている処理はビルドファイルに含まれるのか?

に公開

概要

Goで開発をしていて、どこまでがビルド対象なのか? が気になったので調査した。

テストコードの_testのサフィックスが付いたファイルはビルド対象にはならない、ということはなんとなく知っていたが、それ以外は?

例えば、gomockという有名なモックライブラリがあるが、このライブラリはモックをinterfaceから自動生成する機能を持っている。
自動生成されたモックは当然テスト時にしか使用しない。

これらはビルドに含まれるのか?

結論

アプリケーションから呼び出しがあるもの以外は含まれない、が結論になる

検証

テストコードからしか参照されていないケース

検証用コードの作成

今回の検証ではtest_util.goに定義されている定数TestStrがビルド対象となるかを検証していきます。
test_util.goのTestStrはmain_test.goからしか参照されていないコードを作成します。

ファイル構成

main.go
main_test.go
testutil/test_util.go

main.go

package main

func main() {
	fmt.Println("main")
}

main_test.go

package main

func Test(t *testing.T) {
	fmt.Println(testutil.TestStr)
}

testutil/test_util.go

package testutil

var TestStr = "testutil"

検証

検証にはnmというコマンドを使用。
これはオブジェクト内のシンボルを表示することができるツールで、今回の検証にはうってつけ。

以下のようにgoの実行ファイルを作成後、nmコマンドで実行して検証。

> go build -o bin

> nm bin | grep testutil

>

testutilがビルドに含まれているのであれば、シンボルとしてtestutilが表示されるハズだが、今回は表示されていないので、このバイナリには含まれていないことがわかった。

アプケーションコードとテストコードの両方から参照されているケース

検証用のコードの修正

main.goからtest_util.goの定数を参照するように修正。

main.go

package main

func main() {
	fmt.Println("main")
	fmt.Println(testutil.TestStr)
}

検証

同じようにビルド後にnmコマンドを実行する。

> go build -o bin

> nm bin | grep testutil
000000000055afe0 D test1/testutil.TestStr

今回はシンボルとしてtestutilの定数が含まれていることがわかった。
つまりアプリケーションとして必要だから定数に含まれるようになった。

コンパイラを作る人たちには当たり前の話しかもしれないが、こうして検証してみるといろいろとわかって楽しい。

参考

今回のことはほぼ、以下のstack overflowに記載されていたことを少し修正して試したが、大変参考になった。

https://stackoverflow.com/questions/58932966/are-libraries-for-testing-incorporated-in-final-build

Discussion