読者です 読者をやめる 読者になる 読者になる

テストをテストする方法 #1

Testing

本投稿はずいぶんと前に書いたものですが、せっかくなので公開します。 要求元はたしか@さんだった。

ソフトウェア開発においてテスト自体が正しいかどうかを確認することは非常に困難です。どんなときにテストの正しさを気にするかというと、自分には3つありました。

  1. テストをレビューするとき
  2. テストのリファクタリング
  3. 知らないプロダクトを触るとき

それぞれでどのような施策を打てるかやってみたことを書きます。

テストをレビューするとき

具体的な値を使っているテストは同値内のいずれかの値に変更してみる

テストをレビューするときにテストが正しいかどうかを簡単にまず試す方法としては、入力値を同値内のいずれかの値に変更することです。QuickCheckやランダム値生成などを使っていない貧困なテストでは同値分割ができていない事によるテストもしくはプロダクトのバグが発見できていない場合があります。

テストメソッド名に見合うような同値分割がされているテストであれば、入力値をその同値内で変更してもテストは問題なく通るはずです。このときにテスト結果が入力値に関連したかなり具体的な値になっている場合はもちろんそちらも変える必要があるでしょう。(それがいいか悪いかは別として。実際には悪いと思うけど。)

何によって保守性がわるくなっているのか

この程度のテストコードだとまぁそんなに大きな問題は見つからなさそうに見えますが、実は他にもあって、まとめると次の場合が存在しました。

  • テストの名前と実装があっていない
  • テストでデシジョンテーブルが考慮されていない
  • 入力値によって振る舞いが変わるものが共通化がされていない

名前と実装があっていないというのは多くのテストコードで見かける日本中に蔓延している問題です。これに対してはエンジニアの謎の空気読み取り能力によってなんとかなっていると認識しています。ですが後者2つはそれなりにまた厄介です。

デシジョンテーブルいわゆるロジックが考慮されていないことによって、テストコードが特定のパスのみを保証するなにかになってしまっています。最初からデシジョンテーブルとして成立するようなコードを書くのが難しい時もありますが、できればそのコードを3日以内には特定の値ではなく同値内で動作するように書きなおしましょう。3日は僕の感覚です。

入力値によってというのが実際にはソフトウェアのセットアップ(つまり事前状態をつくること)にも暗黙的に使われている場合に、実際にソフトウェアの操作部分だけの値を変えたら、事前状態とマッチしなくてテストが失敗してしまうことがあります。例えば、すでに作成しているユーザーIDを使ってログインする場合のテストなんかがそうですね。(事前状態ではIDを作成しておいて、テストケース内の操作でそのIDを使ってログインするが、事前状態で作成するIDと操作時に使用するIDが共通化されていないことがって、操作時のIDだけを変えたら、ログインできなくて失敗した)。

テストレベルに応じてAssertの数を制限するようにする

ユニットテストコンポーネントテスト、インテグレーションテスト、システムテストと動かすものが大きくなるほど確認しなければいけないものは多くなる傾向があります。(少なくできているならいい設計だと思います。)

なので、ユニットテストではAssertは1個まで、インテグレーションテストならAssertは4個までと目安を決めてレビューをします。テスト対象の出力で同値分割できていない場合には、各テストレベルでのAssertの項目数を上回ることになります。 実際にテストレベル毎の数は各プロジェクトで決定する必要はあるので試しながらでしかないのですが、最初は小さめの数字から試していって、自分たちのテストコードが嘘をついていないと言えそうな値に調整するといいと思います。

まとめ

ということで、レビューしているときはとりあえず、入力と出力について着目します。 * デシジョンテーブルが意識されているようなテストになっているか * 暗黙的なつながりがないように共通化がされているか * テストレベル毎に妥当な振る舞いの大きさをテストしているか

これらが守られているかを見るために、入力値の変更やAssertの数を見直すということをします。 ではこれらはどうやったら自動で判定できるかというと、入力値はQuickCheckやランダム値生成をうまく使うこと、Assertの数はテストレベル毎にテストコードを管理して静的解析ツールをカスタマイズして検査させること、らへんになります。

では、次回はテストをリファクタリングするときにどうするかです。

新装版 リファクタリング―既存のコードを安全に改善する―

新装版 リファクタリング―既存のコードを安全に改善する―

基本から学ぶソフトウェアテスト

基本から学ぶソフトウェアテスト

広告を非表示にする