【Go言語学習|初心者向け】GoのCIを止めないために!go test -timeoutでテストの「無限待ち」を防ごう

1. 導入:なぜテストのタイムアウト管理が重要なのか

Goで開発をしていると、CI(継続的インテグレーション)環境でテストがいつまでも終わらず、ビルドが止まってしまった経験はありませんか?これは主に、コード内のデッドロックや、外部リソースへの接続待ちなどで発生します。CIの時間が長引くと開発効率が下がるだけでなく、クラウド利用料などのコスト増大にも繋がります。これを解決するのが、Go標準の「go test -timeout」オプションです。

2. 基礎知識:テストフリーズとデッドロック

テストフリーズとは、プログラムが「終わらない状態」に陥ることを指します。特にGoでは、複数のゴルーチンが互いの終了を待ち合う「デッドロック」が発生しやすく、これが起こるとテストプロセスは永遠に終了しません。

go test -timeoutは、指定した時間を超えてテストが完了しなかった場合に、テストプロセスを強制終了させる仕組みです。これを使うことで、万が一のバグによる無限ループやデッドロックが起きても、CIパイプラインを即座に停止させることが可能です。

3. 実装と解決策:CIでの活用方法

CI環境では、デフォルトのタイムアウト(通常10分)に頼らず、プロジェクトの規模に合わせて明示的に設定するのがベストプラクティスです。

設定の考え方:
・小規模なプロジェクト:30秒〜1分
・大規模なプロジェクト:5分〜10分
のように、想定されるテスト実行時間より少し長めの余裕を持って設定します。

4. サンプルプログラム:タイムアウトを体感する

以下のコードは、わざと無限ループを発生させ、タイムアウトによって強制終了される様子を確認するためのサンプルです。

package main

import (
“testing”
“time”
)

// テストが永久に終わらないデッドロックを模した例
func TestInfiniteLoop(t testing.T) {
// 無限ループが発生する状況をシミュレーション
// 実際にはデッドロックなどがここに該当します
for {
time.Sleep(1 time.Second)
t.Log(“処理中…”)
}
}

// 実行方法:
// ターミナルで以下のコマンドを実行してください
// go test -v -timeout 5s .
// 5秒経過すると、プロセスが強制パニックを起こし、スタックトレースを表示して終了します

このコマンドを実行すると、5秒後にGoが自動的にスタックトレース(どこで処理が止まっているか)をダンプしてテストを失敗させてくれます。

5. 応用・注意点:現場での運用

スタックトレースの活用:
タイムアウトが発生した際、Goは「どの関数で止まっているか」を示すスタックトレースを標準エラーに出力します。CIのログを確認する際は、このスタックトレースを追うことで、デッドロックの犯人を特定できます。

注意点:
・タイムアウト時間は「テスト全体の合計時間」です。個別のテストケースが遅いのか、テストの数自体が多すぎるのかを意識してください。
・ネットワーク通信を含むテストがある場合、その通信時間を考慮してタイムアウトを少し長めに設定する必要があります。

CIを安定させることは、チームの心理的安全性を高めることに直結します。ぜひ今日のプロジェクトから、-timeoutオプションを導入してみてください。

コメント

タイトルとURLをコピーしました