JavaでのUT作成基準を整理してみた

チームが小さいとよしなにですむのだけど、大人数になってくると明文化しとかないと結局テストが書かれないのでUTの作成基準とかを整理してみた。

自分のチームで使う想定のイメージで書いてみたけど、体制やプロダクトの性質によっても変わってくるだろうし色んな人のコメントが聞いてみたいところ。

UT作成基準

前提

  • 本ドキュメントではユニットテストJUnitのような単体テストを実行するテストコードと定義します。
  • また、単体テストとはV字モデルにおけるモジュールの詳細設計に基づきメソッドレベルの振る舞いを保証するテストとします。

ユニットテストとは?

ユニットテストは「動く仕様書」です。

ユニットテストはプロダクトコードの振る舞いを保証してくれます。

何故、ユニットテストを書くのか?

品質と安心のために。ユニットテストを書く事で以下のような効果があります。

不具合発生時の問題の切り分け

結合テスト等のフェーズで問題が発生した際に、UTで書かれてる範囲の内容は問題ないと切り分けできます。

そのためデータとかI/Fの不備とか環境不備とか設計/実装レベルの考慮漏れとかに注力できるので修正コストを下げることが出来ます。

改修時のテスト工数削減

リファクタリングや性能改善をした際にユニットテストに書かれている範囲内で差分が無いことを保証できます。

機能改修の場合も修正箇所のテストを見直すだけになるので、影響調査コストを下げることが出来ます。

リグレッションテスト

リグレッションテストを実施することで「想定外の場所に」影響が出てないことを確認することが出来ます。

人手でやった場合には膨大なコストがかかりますが、UTであればリグレッションテストのコストを大きく下げることが可能です。

いつ、ユニットテストを書くのか?

  • コードレビューのタイミングまでに作成してください
  • TDD/BDD的な観点で書くのが推奨ですが、コードレビュー時までに完成していれば必ずしもテストファーストでなくても問題ありません
  • ユニットテストもプロダクトコードと同様に適切なテストケース(=詳細設計がテストとして記述されているか)になっているかのレビュー対象となります

何をユニットテストに書くのか?

詳細設計にもとづく内容をブラックボックス観点で作成してください。原則、以下の観点が必要です

  • 同値分割
  • 境界値分析
  • 無効値/異常系

また、同値分割が適切であることを確認するために、カバレッジを確認してください。

無効値に関しては本来nullが入りえないモジュールで、入った場合は単純にNullPointerExceptionになるケースなどは作成不要です。特にハンドリングしないシステム異常もUTの作成は不要です。

カバレッジはどうするか?

  • 前述のブラックボックス観点が満たせていれば問題ありませんが、参考値として作成/改修したビジネスロジックの90%から100%をブランチ網羅を目標値としてください。
  • 上記の数字にならない場合はレビュー時にレビューアに理由を説明してください。
  • ブランチ網羅の確認にはJaCoCoを利用してください。

ユニットテストを何に対して書くのか?

  • ユニットテストはプロダクトコードのうちビジネスロジックのpublicメソッドに対して作成します。
  • プレゼンテーションレイヤーや、ビジネスロジックであってもprivateメソッド等には実施しません。
  • ログ出力や標準出力のテストも実施しません。ファイル出力も原則テスト不要です。

Tips:

  • 画面への表示順などはモデルとビューを適切に切り離して、なるべくビジネスロジックのUTで検証できるように設計してください。
  • privateメソッドがテストすべき重要なメソッドである場合はpublicメソッドとして実装し、必要があればクラスを分ける等の対応を行ってください。
  • ログ出力や標準出力、ファイル出力は出力前の内容をテストできるように設計してください。

また、ユニットテストは以下の2つに大別します

  • Quick Test
  • Slow Test

Quick Test

Mavenのビルド時に毎回実行されるテストです。

入出力ファイル、DB、外部API等に依存しないJavaの引数と戻り値のみで期待値検証ができるテストケースを作成してください。

なるべくSlow TestではなくQuick Testで動作が保証できるように設計してください。

Slow Test

通常のMavenビルド時には実行されず「testプロファイル」を指定した際に実行されるテストです。

入出力ファイル、DB、外部API等を利用するテストはこちらに記載します。

SQLが重要なビジネスロジックであるようなケースなど結合テストでの実施ではテストコストが高すぎる場合に作成します。

ファイル出力や外部API出力などQuick Testで十分に内容が保証できる場合は、Slow Testを作成せずに結合テストフェーズでの担保で問題ありません。

いつ、ユニットテストを実行するのか?

  • Quick Testはビルド時に常に回します。原則、skipTests=trueを利用してはいけません。
  • Slow TestはPullRequest前などの節目のタイミングで回します。また、CI環境ではDailyまたは日に数回実行します。

まとめ

とりあえず思いつく事をわーっと、書いてみた。他の人はどうしてるのかも知りたいのでいろんな意見求む!

それではHappy Hacking!

関連リンク