Goのtestingパッケージに対する一時的なディレクトリ移動のためのテストヘルパー関数の提案まとめ

testing: add TB.Chdir #62516

github.com

一時的にカレントディレクトリを移動してテスト終了と共に元のディレクトリに移動するヘルパー関数 Chdir(dir string) を testing package に追加する提案を読んだまとめです。 ちょうど3日前の 2024/06/25 に Accepted されました。

具体的な利用シーンには、プログラムの実行箇所に依存するカレントディレクトリの設定ファイルを読み込む関数のテストなどが挙げられます。

ディレクトリを移動したテストを書きたい時はあまり多くはなさそうですが、ディレクトリを移動したのにテスト終了時に元のディレクトリに戻り忘れる、ディレクトリを移動するテストを並列で実行したなどでテストがFlakyになってしまうなんてことはやりそうです。 提案によって追加される testing.Chdir を使わない場合、ディレクトリの戻り忘れについては提案のdescriptionにあるような t.Cleanup() で元のディレクトリに戻る処理を行う関数を自分で定義して使うようにすれば防げますが、テストが並列で実行されていることについては並列で実行されているかを知るためのインターフェイスがないので良い対処方法はなさそうです。

並列テストで起こる問題については提案のdescriptionでも言及されており、Accept された仕様1では対策がなされています。 その対策とは、並列テスト内でtesting.Chdir(dir string) が呼ばれた場合には内部で t/b.Fatal() を呼び出すことです。 つまり、並列テスト内で使った場合にはテストが必ず落ちるようになるため気がつけます。 そのため testing.Chdir() を利用したテストを気がつかずに並列にしてしまうことは起こりません。 testing package 内部であればテストが並列であるかを t.isParallel boolフィールドを参照することで判定できます。

この提案の議論で面白いことは、Russ Cox による標準のtesting packageに追加する価値があるだけの利用頻度の高さや重要性があるかの調査結果をまとめたコメントです 2。 調査内容は次の通りです。全部で8,756,664件の _test.go ファイルから os.Chdir の利用箇所 (全8,756,664ファイルのうち0.27%の23,963ファイル)を検索し、その中から更にランダムに選んだ20ファイルについて提案が役立つかを調べています。

結果は、ランダムに抜き出した20ファイルのうち15ファイルでは os.Chdir を使うことが必要であり、15ファイルのうち5ファイルではos.Chdirでディレクトリ移動後に元のディレクトリに戻る復帰処理が漏れているため他のテストを壊す恐れがあったと述べています。結論では、os.Chdir をテストで利用する頻度は高くはないが問題が起こった場合に修正が困難であるため testing package に一時的にディレクトリを移動するためのヘルパー関数を追加する価値があるとしていました。

ちなみにコードの検索には google/codesearch で公開されている grep と似たコマンドが用いられていました。