「テストしておいて」と言われても、正しい値で一度動かす以外に何を試せばよいか迷う。そんなときは、仕様を入力・事前状態・操作・期待結果へ分けてみます。
先に結論
- 仕様から期待結果を決める。動いた結果に合わせて、正解を書き換えない。
- 代表値と境界の前後を選ぶ。正常に通る値と、拒否される値の両方を試す。
- 権限・状態と「変わらないこと」も確認する。答えが未確定なら、仕様確認へ戻す。
架空の問い合わせ管理を使い、件名の文字数、担当者の権限、状態変更からケースを作ります。JUnitの書き方へ進む前に、何を確かめるかを具体化しましょう。
まず、仕様を入力と期待結果に分ける

題材は、件名が必須で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・配列の範囲外アクセスも役立ちます。
ケースを渡す前のチェック
- 仕様の根拠、入力、事前状態、操作、期待結果を揃えたか。
- 正常な代表値と、拒否する値・境界の前後を選んだか。
- 権限と状態、拒否時に変わらないことを確認したか。
- 期待結果と実際の結果を別に記録したか。
- 未確定の仕様と、実行していない範囲を明記したか。
