とんちゃん の ぐだぐだえびでい

バックエンドエンジニアのとんちゃんが、ぐだぐだな毎日で培った技術情報を綴るブログです。

単体テスト項目を作成する!

資料を漁ってたら、3年前くらいに"単体テスト項目書"を作成するにあたってのレクチャーを受けた時のメモが出てきたので、ここにまとめておきますね。

単体テスト項目書の作成の流れ

ここでいう単体テスト(モジュールテスト)とは、実装したメソッド(モジュール)に対して、仕様通りの動作となっているかを確認することです。

単体テスト項目書は、テスト項目(どんなオペレーションをして、何を確認するか)を明記した資料です。

単体テストは、"ブラックボックス"と"ホワイトボックス"という2つの観点から確認していきます。

ブラックボックステスト

ブラックボックステストって何を確認するの?

ブラックボックステストとは、データの出力パターンを確認するテストです。
入力値と、実行した結果を、仕様と比較することによって、入力と出力の関係/関連が仕様通りかを確認します。

また、無差別に入力データを決定すると、本来必要なパターンが抜けたり、余分なパターンが紛れ込んでしまうため、
そんな無駄を防ぐために、試験として妥当なパターンを定義します。

ブラックボックステストの粒度とは?

ブラックボックステストの粒度は、観点に対するテスト項目の数で決まります。

入力データの選定

仕様に定義されているモジュールの引数の仕様より、入力値(テストデータ)を決めます。
入力値を決める際に、下記の観点にて洗い出すことで、効率的な入力値を設定できます。

境界値
  • 期待する範囲の最大値、最小値(例:月の場合、1と12)
  • 変数の最大値や最小値
固定値
  • 期待する区分値
異常値
  • 期待する区分値以外の、null、0、半角/全角スペース、ブランク文字などの、よくあるやっといて損はないだろう値
  • 期待する範囲の最大値、最小値の外側(例:月の場合、0と13)
  • 変数の最大値や最小値の外側
  • 数値を期待する場合、数値以外の文字列
出力値ってどこからわかるの?

仕様に定義されているはずです。
もし記されていない場合は、仕様を決めた人、または自分の心に聞きましょう。
必要なnullチェックとか忘れてたなら、いさぎよくバグ票を起票しましょう・・・

ホワイトボックステスト

ホワイトボックステストって何を確認するの?

ホワイトボックステストとは、構造化プログラミングにおける、順次、分岐、繰り返しのルートをすべて実行するテストパターンを用意し、意図したルートを通っているか確認するテストです。

ソースコードの全行を網羅することで、意図しない処理や実行エラーの発生がないかを確認します。

ホワイトボックステストの粒度とは?

下記パターンを確認して、パスの通過(カバレッジ=網羅率)を高めるテストを行うことで、プログラムの細部までの保障が可能となります。

カバレッジパターン
  • C0レベル ・・・ 処理経路を構成するすべての命令を最低1回実行します。
  • C1レベル ・・・ すべての条件分岐の真と偽の両方を最低1回実行します。
  • C2レベル ・・・ 条件分岐の真と偽のすべての組み合わせを実行します。繰り返しも複数回実行します。

アプリケーションの修正によって、分岐が追加になったり消えたりした場合は、対象メソッドについてホワイトボックステストのパターンを洗い出し直して、全てやり直します(自動テスト化してあると楽です)

そもそもどうやって確認するの?

分岐ごとにデバッグログを埋め込んで、正しいパターン表示となっているかを確認します。

public String hoge(String argString1) {
    // デバッグログ(メソッド名_パス階層分の連番)
    logger.debug("hoge_1");

    // 定義
    String returnString = "引数は ";

    // 引数の状態を表示する
    if ( argString1 == null ) {
        // デバッグログ(メソッド名_パス階層分の連番)
        logger.debug("hoge_1-1");

        returnString += "null";
    } else if ( "".equals(argString1) ) {
        // デバッグログ(メソッド名_パス階層分の連番)
        logger.debug("hoge_1-2");

        returnString += "blank";
    } else {
        // デバッグログ(メソッド名_パス階層分の連番)
        logger.debug("hoge_1-3");

        returnString += "文字列";
    }

    // デバッグログ(メソッド名_パス階層分の連番)
    logger.debug("hoge_2");

    returnString += " でございます。";

    return returnString;
}

または、djUnitなどのカバレッジ測定ツールを使用する方法もあります。
djUnit - dJWiki

試験項目書の作成

次に、ホワイトボックスとブラックボックスの観点から、テストの確認事項を洗い出してみましょう。
パス一覧と出入力表を作成します。

パス一覧の作成

ホワイトボックステストの観点での確認をパス一覧にします。
ソースコードの分岐箇所を元に、C2レベルでパスのパターンを一覧に起こします。
通過ログをもとに、

パス1
1
1-1
2
パス2
1
1-2
2
...

といった具合にあげていきます。

出入力表の作成

次に、ブラックボックステストの観点での確認を出入力表にします。
出力パターンを一覧にして、それに対する入力パターンを並べます。
出力パターンとは、正常系出力、業務異常系出力(期待しない結果、またはエラー)、実行時異常系出力(エラー)のことです。

出力 入力
"引数は null でございます。" null
"引数は brank でございます。" ""
"引数は 文字列 でございます。" "1"
"引数は 文字列 でございます。" "0"
"引数は 文字列 でございます。" "あああ"

といった問い合った具合にあげていきます。

両表を紐づけて、試験項目書とする

その後、パス一覧と出入力相対表を紐づけます。

試験ID 出力 入力 パス
1 "引数は null でございます。" null 1
2 "引数は brank でございます。" "" 2
3 "引数は 文字列 でございます。" "1" 3
4 "引数は 文字列 でございます。" "0" 3
5 "引数は 文字列 でございます。" "あああ" 3

といった具合に紐づければ、試験項目書の完成です!

作成中の気を付けるコト

試験項目の抜け漏れを防ぐために、以下で確認します。

  • ソースコードと処理パターン表を突合せて、全通過パターンを網羅できているかを確認します。
  • ソースと入出力相対表を突合せて、出力と入力のパターンが網羅されているかを確認します。
  • パス一覧と入出力相対表を突合せて、全てのパターンが紐づけされているかを確認します。
  • 出入力相対表と試験項目書を突合わせて、全てのパターンが書き出されているかを確認します。

おわりに

以上の作業を、末端のモジュールから行っていきます。

この作業をすると、ソースをじっくり読むので、机上レビューをついでに行えますー。
が、仕様通りの実装かは確認できるのですが、仕様が正しいかという観点での確認は行えませんです。。

あとは、境界値のバリエーションが増えたらいいなぁー。

追記(2014/06/11)
心優しい先輩が突っ込んでくれたので、色々直してすます。
文章って難しい。。