はじめに (対象読者・この記事でわかること)

この記事は、GoでCLIツールやマイクロサービスを開発しているけれど「本番ビルドにテストコードが含まれて容量が無駄に増えていないか」と気になっている方を対象にしています。
記事を読むことで、Goのビルドシステムがテストファイルをどう扱うか、実際のバイナリサイズに与える影響の有無、さらに「本番ビルドを最小化するためのTips」まで身につきます。社内のインフラチームから「Goのバイナリ重くない?」と指摘を受えたことをきっかけに検証を始めたので、その成果を共有します。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Goの基本的なプロジェクト構成(main.goxxx_test.goの存在) - go buildgo testの違いを踏んだことがあること - ターミナルでls -lhなどのコマンドが打てること

Goのテストファイルはビルドに含まれるのか?その疑問

Goは言語仕様としてテストファイル(*_test.go)を標準でサポートしていますが、「これ本番バイナリに混じってないよね?」という不安は開発者なら誰しもが一度は抱えます。特に、テストヘルパー関数やモックまで含めるとファイルサイズが無視できないレベルになることもあります。そこで、まず公式ドキュメントを確認すると、

go build*_test.go無視する

と明記されています。しかし、実際の挙動を信用せずに検証してみるのがGoらしい(?)姿勢です。ということで、検証環境を用意してみましょう。

実験:テストコードの有無でバイナリサイズはどう変わる?

ステップ1:実験用プロジェクトを作成

適当なディレクトリで以下を実行します。

Bash
mkdir go-binary-test && cd go-binary-test go mod init example.com/test

main.go(本体)とmain_test.go(テスト)を作成します。

Go
// main.go package main import "fmt" func main() { fmt.Println("Hello, production!") } func Sum(a, b int) int { return a + b }
Go
// main_test.go package main import "testing" func TestSum(t *testing.T) { if got := Sum(1, 2); got != 3 { t.Errorf("Sum(1, 2) = %d; want 3", got) } } // さらに巨大なヘルパー func BenchmarkSum(b *testing.B) { for i := 0; i < b.N; i++ { _ = Sum(i, i) } }

ステップ2:テストあり/なしでビルドして比較

まず、現状(テストあり)でビルド:

Bash
go build -o with_test ls -lh with_test # -rwxr-xr-x 1 kousukei staff 2.0M 1 1 00:00 with_test

次に*_test.goを一時的に退避:

Bash
mkdir test_backup && mv *_test.go test_backup/ go build -o without_test ls -lh without_test # -rwxr-xr-x 1 kousukei staff 2.0M 1 1 00:01 without_test

サイズは同じです。テストファイルの有無はバイナリサイズに影響しません。

ステップ3:さらに極端な例を試す

退避していたテストを戻し、巨大なモックデータを追加してみます。

Go
// mock_test.go package main var mockData = [1024 * 1024]byte{} // 1MBの静的データ

ビルドしても、依然として2.0Mのまま。-ldflags="-s -w"で更に削減:

Bash
go build -ldflags="-s -w" -o trimmed ls -lh trimmed # -rwxr-xr-x 1 kousukei staff 1.4M 1 1 00:02 trimmed

ハマった点やエラー解決

検証中、「テストファイルにinit()関数を書いたらビルドに入り込むのでは?」と心配になりました。実際に以下を追加:

Go
func init() { println("test init") }

しかし、ビルド後に実行してもtest initは表示されず、やはりテストファイルのinitは実行されないことが確認できました。

解決策

Goのビルドシステムはテストファイルを完全に無視するため、テストコードが本番バイナリに影響することはありません。
もしサイズを削減したい場合は以下を検討してください:

  • -ldflags="-s -w"でシンボルとDWARF情報を削る(30〜40 %削減)
  • upx --bestで圧縮(更に30 %削減、起動速度とのトレードオフ)
  • CGO_ENABLED=0で静的リンク化

まとめ

本記事では、Goのテストコードが本番バイナリに与える影響を実験的に検証しました。

  • テストファイル(*_test.go)はビルドに一切含まれない
  • 巨大なモックデータやinitを書いてもサイズは変わらない
  • バイナリ削減はリンカフラグや圧縮ツールで対応すべき

この記事を通して、「テストコードを書くことで容量が増える心配は不要」という安心感を得られれば幸いです。
次回は、-ldflagsの細かいチューニングや、Dockerマルチステージビルドで最小イメージを作る手法を深掘りします。

参考資料