テストケースの作り方|仕様から正常系・境界値・異常系を出す例

広告 設計・テスト・レビュー

テストケースの作り方|仕様から正常系・境界値・異常系を出す例

「テストしておいて」と言われても、正しい値で一度動かす以外に何を試せばよいか迷う。そんなときは、仕様を入力・事前状態・操作・期待結果へ分けてみます。

先に結論

  • 仕様から期待結果を決める。動いた結果に合わせて、正解を書き換えない。
  • 代表値と境界の前後を選ぶ。正常に通る値と、拒否される値の両方を試す。
  • 権限・状態と「変わらないこと」も確認する。答えが未確定なら、仕様確認へ戻す。

架空の問い合わせ管理を使い、件名の文字数、担当者の権限、状態変更からケースを作ります。JUnitの書き方へ進む前に、何を確かめるかを具体化しましょう。

まず、仕様を入力と期待結果に分ける

仕様を分ける:件名・権限・状態。観点を出す:境界と許可条件。具体値を選ぶ:0・1・2文字と99・100・101文字。期待結果を書く:結果と変化しない状態
仕様を入力と期待結果へ変換する

題材は、件名が必須で1〜100文字、状態が下書き・受付済み・対応中・完了で、投稿者と担当者がいる問い合わせ管理です。ただし、文字数の数え方や空白、誰がどの状態へ変更できるかまで決まらないと、期待結果は書けません。

この練習では、次を追加の架空仕様として決めます。現場へ無断で採用する仕様ではありません。

  • 件名:null・空文字・空白だけを拒否。前後の空白は自動削除せず、Unicodeコードポイントで1〜100と数える。
  • 権限:対応開始は現在の担当者だけ。投稿者という理由だけでは許可しない。
  • 状態:受付済みから対応中へ変更する。他の状態からの対応開始は拒否。
  • 拒否時:元の状態を変えない。表示文やHTTPステータスは、実システムの別の契約として決める。

仕様が未確定なら期待結果は「要確認」です。現在のコードが受け付けたから正常とすると、既存の不具合を正解にする可能性があります。

同じ扱いになる値から、代表を選ぶ

1〜100文字のすべてを最初から試す必要はありません。同じように処理されると考えられるまとまりに分け、代表値を選ぶのが同値分割です。

ただし、拒否される値を一つにまとめすぎないでください。nullは値なし、空文字は長さ0、空白だけは文字数があっても認めない条件です。別々に確認します。Javaでの区別はisEmptyとisBlankの違いが参考になります。

技法の定義はISTQBのFoundation Levelシラバス4.0.1の4.2節で確認できます。以下は、その考え方を問い合わせの独自仕様へ当てはめた例です。

境界では、許可と拒否の前後を見る

上限100文字を100未満と実装すると、100文字を誤って拒否します。101以下なら101文字を誤って許可します。普通の長さでの成功だけでは見つかりません。

今回は0・1・2文字と、99・100・101文字を試します。境界と両隣を選ぶ、3値境界値分析の考え方です。0文字は空文字のケースと重なるので、目的を注記して一つにまとめられます。

入力・観点期待結果
null(値が必要)拒否
空文字・0文字(下限の外)拒否
a、aa(下限と隣)どちらも許可
aを99個、100個(上限と隣)どちらも許可
aを101個(上限の外)拒否
半角空白、全角空白(空白だけ)どちらも拒否
😀を100個、101個(数え方)100個は許可、101個は拒否

絵文字の行では、境界に加えて数え方も確かめます。JavaのString.length()はUTF-16のコード単位数を返し、今回のコードポイント数とは一致しない場合があります。Java 17のString公式仕様が参照先です。

文字数の数え方に注意

コードポイントと、人が一文字と感じる単位も常に一致しません。結合文字や複数コードポイントの絵文字を「見た目の一文字」で数える要件なら、今回の仕様を使わず、数え方を別に決めます。

権限と状態は、事前条件を揃えて比べる

「担当者なら成功」だけでは、投稿者による誤った更新や、完了した問い合わせの再開を見逃します。練習では投稿者をID 10、担当者をID 20、無関係の利用者をID 30とします。すべて架空の値です。

以下で試す操作は、すべて「対応開始」です。

受付済みの問い合わせで、操作する人を変える

  • 担当者20:成功し、対応中になる。
  • 投稿者10:拒否し、受付済みのまま。
  • 無関係の30:拒否し、受付済みのまま。
  • 担当者未設定・利用者20:拒否し、受付済みのまま。

担当者20で、現在の状態を変える

  • 下書き:拒否し、下書きのまま。
  • 対応中:拒否し、対応中のまま。
  • 完了:拒否し、完了のまま。

「変わらないこと」も期待結果です。エラーが出ても、その前にDBを更新していたら仕様を満たしません。保存処理があるなら、応答と保存後の状態を確認します。

最初は権限だけ、状態だけを変えると切り分けやすくなります。その後、組合せで結果が変わる箇所を追加します。独立検証では4状態×3利用者の12通りと、担当者未設定の1通りを試しました。この13通りで、すべてを網羅したという意味ではありません。

別の人も実行できるケースに仕上げる

「101文字でエラー」だけでなく、準備するデータ・操作・期待結果を揃えます。保存を試すなら、画面・API・DBのどこを見るかも添えます。

記入例|101文字の件名で保存する

  • 事前条件:受付済みの問い合わせを、担当者20で操作する。
  • 入力・操作:件名にaを101個入れ、保存を押す。
  • 期待結果:件名エラーが表示され、元の件名と状態は変わらない。
  • 実際の結果:実行後、期待結果とは別の欄へ記録する。

仕様書の節や合意したIssueなど、期待結果の根拠も残します。失敗したケースを実際の動きに合わせて合格へ書き換えないために、期待結果と実際の結果は別欄にします。

この例で実行した範囲

件名11件、権限・状態13件は、Java 17.0.8の独立した判定コードで実行して通過しました。DB更新・HTTP応答・ブラウザでの保存は含みません。

練習仕様と判定コードの対応までの確認です。保存先へつないだら、拒否時に更新されないことをその境界でも確認します。

期待結果が決まらなければ、仕様確認へ戻る

「投稿者と担当者が同じ人なら」「完了後に再開できるか」「前後の空白を取り除いてよいか」は、コードだけでは決めない問いです。担当者としての権限だけでよいか、別の承認が要るかも具体例で確認します。

未決事項を見つけたことも、テストを考える成果です。「この入力・状態で、どの結果を保証するか」を一つずつ示すと、仕様を決める人が判断しやすくなります。

ケースが決まったらServiceをJUnit・Mockitoでテストする方法へ進めます。数値の端や空の要素を扱う別の例として、List・配列の範囲外アクセスも役立ちます。

ケースを渡す前のチェック

  • 仕様の根拠、入力、事前状態、操作、期待結果を揃えたか。
  • 正常な代表値と、拒否する値・境界の前後を選んだか。
  • 権限と状態、拒否時に変わらないことを確認したか。
  • 期待結果と実際の結果を別に記録したか。
  • 未確定の仕様と、実行していない範囲を明記したか。

テストの価値を深めるための一冊

何をテストとして残すかを考えたい人には、『単体テストの考え方/使い方』が選書候補です。出版社の紹介と実務担当の本棚で内容を確認できます。

C#例を使う本で、JUnitの操作入門ではありません。本人の読後体験は根拠としていません。本棚にはアフィリエイトリンクを含みます。記事の表やチェック項目は、購入せずに使えます。

-設計・テスト・レビュー
-