@ledsun blog

無味の味は佳境に入らざればすなわち知れず

レガシーコードと闘う Web画面の単体テストケースの作成方法

既に稼働しているWebシステムの修正を依頼された時にはどうしたら良いでしょうか?修正自体はコードを読めば何とかなるかもしれません。しかし、その修正が既存の機能を壊していないことを確認するには?実際に一通りの機能を動かして確認するしかありません。レガシーコードと闘うにはテストが必要です。
まずは画面単位の単体テスト、単一画面の動作を確認方法(テストケース)を考えてみましょう。

はじめに

テストケースを作成するには

テストケースとは入力に対する出力が想定通りか確認するための内容です。漏れのないテストケースとは、想定される入力と入力値の組み合わせを網羅していることです。というわけでWeb画面の入力を考えてみましょう。
また、画面が実現する機能を満たしているか?という観点だけでは、十分なテストケースを作ることができません。なぜでしょうか?機能の確認という視点では「登録画面で入力した情報がDBに保存されているか」など機能が正常に動いているかどうかの確認を行います。しかし、実際のWebアプリケーションでは、パスワードなどの必須な入力値が入力されていない場合の動作、電話番号を入れる入力欄に漢字を入力した場合の動作なども考慮をしなければいけません。テストケースを作成する際には、こういった準正常系の確認を見落としがちなので注意が必要です。

今回は考えません

たとえばユーザ情報登録機能では次のように登録画面と確認画面間でデータを受け渡しが行われます。

  1. 登録画面にユーザ情報を入力
  2. 確認画面に遷移し、登録ボタンを押す
  3. DBのレコードを更新

今回はこういった複数の画面間が連携して実現する機能の確認は考えません。

Web画面の入力

Web画面の入力の組み合わせには、ページを表示する際と表示した後のユーザ操作の二つがあります。

ページを表示する際の入力

ページを表示する際の入力は以下の三つです。

  • URL(クエリ文字列、RESTfulなURLそのもの)
  • クッキー
  • セッションに保持した値

この三つの入力の入力値のパターンを網羅することで、漏れのないテストケースが作成できます。ここでの入力値は関数の入力値と違い、値を設定しないこともできる点に注意が必要です。

_ URL(クエリ文字列) クッキー セッション
値が指定されている場合 1 2 3
値が指定されていない場合 4 5 6
不正な値が指定されている場合 7 8 9

少なくとも上記の9パターンのテストケースが必要です。さらに値が指定されている場合は、関数のテストケースを考えるのと同様に入力値の境界値を洗い出す必要があります。あとは、ひたすらソースからクエリ文字列とクッキー、セッションの値を処理している箇所を読み取ることでテストケースを洗い出すことができます。システムによっては不正な値のチェックなど入っていないでしょう。そんな時はすぐに直さず、淡々と一つずつ記録して次のテストケース作成に進むとよいでしょう。

ページを表示した後の入力(ユーザの操作)

ページを表示した後の入力はユーザの操作です。ユーザの操作は画面に表示されるコントロールの操作を組み合わせたものです。まずコントロールを洗い出し、ユーザの操作の洗い出し漏れを防ぎます。コントロールには次のものがあります。

システムへ動作を要求するもの

  • ボタン
  • リンク
  • キー入力(Enterキーの押下を入力確定にしている場合)

値を変更するもの

Webではサーバで処理はリクエスト単位でしか行われないため、システムへ動作を要求するコントロールの操作がすべての入力になります。その時に参照する値を変更するコントロールを考えればすべての入力値を洗い出すことができます。

しかし単純に入力値の組み合わせをすべて網羅しようとすると、画面に表示しているすべてのコントロールの値の組み合わせとなり膨大なテストケースとなってしまいます。例えばセレクトボックスやラジオボタンなどで三値持つコントロールが10個あった場合は3の10乗、つまり59049パターンになります。これをすべての入力毎に確認することはほとんど不可能です。

そこで最低限確認すべき入力と入力値の組み合わせを洗い出すために、ユースケースシナリオを作成します。まず「システムへ動作を要求する」コントロールを操作した際に実現する機能として正常シナリオを作成します。さらに正常シナリオを満たさないようなパターンとして、セカンダリシナリオ、例外シナリオを作成します。ログイン画面の例を示します。

  • 正常シナリオ
    1. ユーザはユーザIDに自分のユーザIDを入力する。
    2. ユーザはパスワードに自分のパスワードを入力する。
    3. ユーザはログインボタンを押す。
    4. システムはユーザIDとパスワードの対応をチェックして、メニュー画面を表示する。
  • セカンダリシナリオ
    1. 正常シナリオステップ2でユーザが入力したユーザIDとパスワードが対応していなければ「ユーザIDまたはパスワードに誤りがあります。」というエラーメッセージを表示する。
  • 例外シナリオ
    1. ユーザが入力したユーザIDが半角英数でなければ「ユーザIDは半角英数字で入力してください。」というエラーメッセージを表示する。

このように作成したユースケースシナリオからテストケースを作成します。こうして効率よく機能を確認する入力と入力値の組み合わせ(テストケース)を作成することができます。そもそもソースからユースケースを読み取るには、誰がいつ使うどういう機能か想像する必要があります。もしかすると間違った想像かもしれません。結局は勘と経験で推測して、度胸で決めるしかません。

おわりに

レガシーコードとの戦いでしんどいのは、曖昧な仕様をその都度判断しなければいけないことです。ソースから仕様を一つ読み取り、確定と判断しても、その20行下にはまた意味不明のコードが待っているのです。ただひたすら闘い続ける根性のみが必要なのです。