ScalaTestのParallelTestExecutionを使ってスイート内のテストケースをシンプルに並列実行する
sbtのテストスイート並列実行機能と混同しやすいので注意
- クラス単位で並列実行するか
- クラス内のテストケースを並列実行するか
は全く別の話です.
ここは混同しやすく混同した解説がネット上に存在して私も混同してしばらく錯乱していました.
ここにはScalaTestを使った後者のクラス内のテストケースを並列実行する方法について書きます.
前者については sbtにおけるテストの並列実行の設定詳細解説 - xuwei-k's blog を読むと良いと思います.
なお私が作業しているプロジェクトではforkを使っているためデフォルトではクラスごとの並列実行は行われませんでした.
そこでtestForkedParallel
を使ってみたら,
it
単位では出力はまとまったままですが,
実行クラスの表示やbehavior of
での文字列表示にit
の結果表示が混ざってしまって出力が崩壊しました.
ボトルネックになっているテストクラスが十分に重たかったのであまり速度が変わらなかったので使わないことにしました.
ScalaTestの機能を使わない方法
まずScalaTestの機能を使わない方法について述べます.
通常のScalaでのプログラミング同様
- akka-streamの
mapAsync
を使って並列に実行する - scala-parallel-collectionsの
par
を使って並列に実行する
などの方法があります.
私は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
を使うとテスト結果の表示がバラバラになったり,
キャンセルがうまく動かなくなったりするので,
既に自前のプログラムで並列に動かせるならばわざわざ乗り換えなくて良い気がしてきました.
手軽に並列にするのなら良いのですが…