時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

Goの並列テストが何並列で実行されるのかを知りたい

Goの並列テストそのもにについては、Mercari Engineer Blogで@yoshiki_shibataさんによって解説されているこの記事が有名かと思います。

engineering.mercari.com

並列に実行されるということは、これはレースコンディション問題に対するテストケースの作成にも利用できるわけです。 sync.Cond などを使わずにできるので便利ですね。

とはいえ、何並列まで同時に実行してくれるのかが分からないと、このような用途ではちょっと困ります。

たとえば、適当な数のテストを並列で走らせるとして、実際の並列実行数を並列テストの数が下回るぶんには正常に実行できますが、それを大きく上回るとデッドロックを起こす場合があります。

そして、実際の並列実行数は最初に貼った記事のとおり-parallelオプションかあるいはそのデフォルト値であるGOMAXPROCSによるので、すなわち環境依存で失敗しえるテストになってしまいます。 環境依存で失敗しえると本当の失敗を見逃しやすくなってしまうのでよろしくありません。

これを解決するためには、小さな数に並列テスト数を固定してしまう手もありますが、あまり小さな並列数に固定してしまってはレースコンディションが起きそうな状況を引き起こせる確率が低く、また十分に低くなければ前述のように実行環境依存でらデッドロックを引き起こしてしまいかねません。

かといって並列実行数を得られるインターフェイスは提供されていなさそうです。

じゃあ無理やり取るかというわけで暴力です。暴力は全てを解決する……。

func mustGetParallelCount() int {
    tp := flag.CommandLine.Lookup("test.parallel").Value.String()

    parallel, err := strconv.Atoi(tp)
    if err != nil {
        panic(err)
    }

    return parallel
}

こんな感じで取れます。flagはCommandLineという変数にグローバルなコマンドライン引数の処理結果を持っているのでそこからLookupすれば取れるという寸法です。

これを使って並列テスト数を調整したり、場合によってはテストケースごとSkipするなどすればよさそうです。めでたしめでたし。

とはいえ、若干筋悪っぽい感じもするのもっとで良いアイデアあったら教えて下さい。