jestにおけるアサーション数の制限について
jest/max-expects
eslint-plugin-jest
に、テスト毎にexpect
の回数を制限するmax-expects
のルールを提案して、Pull Requestを出して、v26.6.0でリリースしてもらった。
なのでeslint-plugin-jest
のv26.6.0からjest/max-expects
をrules
に追加すると
{
...,
"rules": {
...,
+ "jest/max-expects": ["error", { "max": 2 }]
}
}
test
の中でmax
オプションの上限値を超えてexpect
を使ってアサーションしている箇所では、以下のようにESLintがエラーを報告するようになった。
Too many assertion calls (3). Maximum allowed is 2.
max
オプションのデフォルトは5
で、これはava/max-asserts
のオプションのデフォルト値を参考にしている。
検知できる範囲としてあくまでAST解析して見分けられるものが対象だと思うので、for
文のような形で繰り返しexpect
が実行されるようなケースまではカバーできない認識(prefer-each
のルールが追加されると、それらのルールの組み合わせで結果的に防げるようになるかも?)。
テストにおけるアサーションの数について
上述のESLintのルールは、jestのテストにおけるアサーション数を制限するものだけど、そもそもテストのアサーション数が少ないことを望ましいとする背景は何か。
Assertion Roulette
XUnit Test Patternsでは、Behavior Smells
(テスト実行中の臭い)のカテゴリで紹介されているAssertion Roulette
がある。
これはテストランナーが失敗を出力しても、どのアサーションで失敗したかを特定できないような状況をさしている。
A test fails. Upon examining the output of the Test Runner (page X), we cannot determine exactly which assertion had failed.
明確にそれぞれアサーション毎にテストを分けた方が失敗した時に原因の切り分けがしやすいということがある。
また、失敗したあとのアサーション結果を隠してしまう問題がある。
例えば、1つのテストで3回expect
を実行している場合に、2つ目のexpect
で失敗すると3つ目のexpect
はテスト結果が分からない(そうじゃないテストランナーもあるのかもしれない?)ので、失敗かもしれないしそうじゃないかかもしれない。
一般的なテスティングフレームワークでは、アサーション失敗時に例外が発生し、そのテストメソッドの実行は打ち切られます。
1つのテストに1つのアサーションが理想的という考え方がある。ただ、あくまで理想的にはということであって、1つのテストに必ずアサーションを1つとするのではなく論理的なコンセプトを1つとするくらいで考えるべきかもしれない。
My guideline is usually that you test one logical CONCEPT per test. you can have multiple asserts on the same object. they will usually be the same concept being tested.
Discussion