• 作成:
  • 更新:

ScalaTestのParallelTestExecutionを使ってスイート内のテストケースをシンプルに並列実行する

sbtのテストスイート並列実行機能と混同しやすいので注意

  • クラス単位で並列実行するか
  • クラス内のテストケースを並列実行するか

は全く別の話です.

ここは混同しやすく混同した解説がネット上に存在して私も混同してしばらく錯乱していました.

ここにはScalaTestを使った後者のクラス内のテストケースを並列実行する方法について書きます.

前者については sbtにおけるテストの並列実行の設定詳細解説 - xuwei-k's blog を読むと良いと思います.

なお私が作業しているプロジェクトではforkを使っているためデフォルトではクラスごとの並列実行は行われませんでした. そこでtestForkedParallelを使ってみたら, it単位では出力はまとまったままですが, 実行クラスの表示やbehavior ofでの文字列表示にitの結果表示が混ざってしまって出力が崩壊しました. ボトルネックになっているテストクラスが十分に重たかったのであまり速度が変わらなかったので使わないことにしました.

ScalaTestの機能を使わない方法

まずScalaTestの機能を使わない方法について述べます.

通常のScalaでのプログラミング同様

などの方法があります.

私はScalaTestの並列実行方法を当初知らなかったので当初使っていましたがScalaTestの機能を使うほうが良いでしょう.

ただテストスイートの一部のテストだけを並列実行したい場合などには柔軟性があり需要があるかもしれません.

ParallelTestExecutionを使う方法

ParallelTestExecution というtraitがありこれをテストスイートが実装するとそのテストスイートのテストは並列実行されます.

再度確認するとこのScalaTestのtraitであるParallelTestExecutionはテストスイート(テストクラス)毎の並列実行には関係していません. それはsbtが制御する領域です. このtraitはテストスイート内部のテストを並列実行するためのものです.

ParallelTestExecutionを使うに当たって注意があります. これを実装したテストスイートでは各テストは個別のクラスインスタンスで実行されます.

私はParallelTestExecutionの機能を誤解していたため, scala-parallel-collectionsを使ったままParallelTestExecutionを導入してしまいました. そして各コレクションに対するmapがテスト実行ごとに全部実行されてしまい超絶遅いテストが出来上がってしまいました.

ParallelTestExecutionを使う時は遅い動作こそinの中になるべく全てを書くことにしましょう.

ボイラープレートを処理する関数を定義してテストデータをVectorに入れてforeachするのは特に問題ありません.

ParallelTestExecutionに切り替えてakka-streamを使ったテストと速度を比較してみたのですが, 誤差レベルの差しか無かったのでこの方法で特に問題は無いようです.

追記: ScalaTestの機能使わない方が良いかもしれません

実際そこそこ使ってみるとわかったことがあります.

ParallelTestExecutionを使うとテスト結果の表示がバラバラになったり, キャンセルがうまく動かなくなったりするので, 既に自前のプログラムで並列に動かせるならばわざわざ乗り換えなくて良い気がしてきました.

手軽に並列にするのなら良いのですが…