同値分割と境界値分析は、「テストケースを減らしながら、バグが出やすい場所は外さない」ための技法です。この2つはセットで使います。
実務でより重要なのは、テスト実行時ではなく仕様レビューの段階で使うことです。境界を書き出すと、「仕様書にその値の扱いが書かれていない」という抜けが必ず見つかります。実装前にそれを潰せるかどうかで、後工程の手戻りが大きく変わります。
この記事では、2つの技法の基本と、実務で漏れやすい境界(文字数・日付・全角数字)まで具体例で解説します。
スポンサーリンク
同値分割とは
「同じ結果になるはずの入力」をグループにまとめ、各グループから代表値を1つだけ選ぶ技法です。
年齢入力欄(0〜120歳)を例にすると、次のように分けられます。
| クラス | 範囲 | 代表値 |
|---|---|---|
| 有効値クラス | 0〜120 | 30 |
| 無効値クラス(下) | -1以下 | -5 |
| 無効値クラス(上) | 121以上 | 130 |
根拠は「同じクラスの中なら、どの値を入れても同じ処理を通る」という前提です。30 で通るなら 31 も 32 も通るはずなので、全部試す必要はありません。
この前提が崩れる場合は分割し直します。 たとえば「20歳未満は購入不可」という別の条件が加わるなら、有効値クラスをさらに「0〜19」と「20〜120」に分ける必要があります。
境界値分析とは
同値クラスの「境目」を狙う技法です。 不具合は範囲の真ん中ではなく、ほぼ境界で起こります。< と <= の書き間違い、i < n と i <= n の取り違えが原因です。
年齢入力欄の境界値は次のようになります。
-1 | 0 ... 120 | 121
↑ ↑
下の境界 上の境界
2値と3値のどちらを使うか
境界値分析には2つの流儀があります。どちらを使うかをチームで決めておかないと、担当者ごとにテストケース数がばらつきます。
| 取る値 | 年齢の例(0〜120) | ケース数 | |
|---|---|---|---|
| 2値 | 境界と、その外側の隣 | -1, 0, 120, 121 | 4 |
| 3値 | 境界と、その両隣 | -1, 0, 1, 119, 120, 121 | 6 |
通常は2値で十分です。 3値は、境界付近の処理が特に複雑な場合や、事故が起きたときの影響が極端に大きい場合(決済金額の上限など)に使います。
スポンサーリンク
2つの技法の関係
同値分割で「どこを見るか」を決め、境界値分析で「どの値を入れるか」を決めます。 順番が逆になることはありません。
- 同値分割:入力の範囲をグループに分ける → テストすべき箇所が明確になる
- 境界値分析:各グループの境目を特定する → 実際に入れる値が決まる
この2つを組み合わせると、「代表値1つ+境界値」だけで、範囲全体をカバーしたことにできます。0から120まで121通り試す必要はありません。
実践例1:年齢入力欄
仕様:年齢は0〜120歳の間で受け付ける。
| 値 | 期待結果 | 技法 |
|---|---|---|
| -1 | エラー | 境界値 |
| 0 | OK | 境界値 |
| 30 | OK | 同値分割(代表値) |
| 120 | OK | 境界値 |
| 121 | エラー | 境界値 |
ここで止めてはいけません。 数値の境界だけを見ていると、実務では次の抜けが残ります。
| 入力 | 仕様に書かれているか |
|---|---|
| 空欄 | 必須なのか任意なのか |
| 全角数字「30」 | 受け付けるのか、変換するのか、弾くのか |
| 小数「30.5」 | 整数のみか |
| 前後に空白「 30 」 | トリムするのか |
| 文字列「abc」 | エラーメッセージは何になるか |
この表を作って開発者に見せると、たいてい何行かは「決まっていない」と分かります。 それを実装前に潰すのが、この技法の一番の価値です。
スポンサーリンク
実践例2:クーポン適用条件
仕様:購入金額が1,000円以上の場合にクーポンを適用する。
| 値 | 期待結果 |
|---|---|
| 999円 | 適用されない |
| 1,000円 | 適用される |
| 1,001円 | 適用される |
「1,000円以上」の日本語は、1,000円ちょうどを含みます。 しかし仕様書に「1,000円を超えた場合」と書かれていたら、1,000円ちょうどは含みません。この違いが実装の >= と > の差になります。
金額の場合、確認すべき点がもう一つあります。
- 判定に使うのは税込か税抜か:仕様書に書かれていないことが非常に多い
- 送料は含むか
- 他のクーポンで割引された後の金額か、割引前か
「1,000円以上」という短い一文に、これだけ確認事項が隠れています。
実践例3:パスワードの文字数
仕様:パスワードは8〜16文字。
| 文字数 | 期待結果 |
|---|---|
| 7文字 | エラー |
| 8文字 | OK |
| 16文字 | OK |
| 17文字 | エラー |
文字数の境界では「1文字をどう数えるか」が問題になります。 ここは実務で最も漏れやすいポイントです。
- 絵文字:JavaScript の
lengthでは絵文字1つが2文字と数えられます(サロゲートペア) - 結合文字:「が」を「か」+濁点で表現すると2文字になります
- 改行:
\r\nは2文字。OSによって送信される文字数が変わります - 全角文字:バイト数で制限している実装なら、全角は3バイト(UTF-8)
「16文字」の定義がフロントエンドとサーバーで食い違っていると、画面では通るのに保存でエラーになります。 絵文字を1つ入れたテストケースを必ず1本入れてください。
日付の境界は特に注意する
日付は境界の見つけ方が数値と違います。範囲の端だけを見ていると漏れます。
| 境界 | 例 |
|---|---|
| 月末 | 1月31日、4月30日 |
| うるう年の2月29日 | 2024-02-29(2100年はうるう年ではない) |
| 年またぎ | 12月31日 → 1月1日 |
| 日付の変わり目 | 23:59:59 → 00:00:00 |
| タイムゾーン | UTCとJSTで日付が1日ずれる時間帯 |
「今日から30日後」のような相対日付の仕様では、実行するタイミングによって結果が変わります。 テストは日付を固定できる状態で書いてください。
無効値は1つずつ変える
これは技法そのものより、テストケースの書き方の話です。 無効値を複数同時に入れてはいけません。
悪い例:年齢に「-1」、名前を空欄、メールを不正形式 → まとめて1ケース
→ エラーになったが、どの項目で弾かれたのか分からない
良い例:他の項目はすべて正常値にして、年齢だけ「-1」にする
→ 年齢のバリデーションが動いていることが確認できる
複数の無効値を同時に入れると、最初に検出された1つでエラーになり、残りのチェックが動いているかどうか確認できません。「実は年齢のチェックが実装されていなかった」という不具合を見逃します。
逆に有効値は組み合わせて構いません。すべて正常な値を1ケースで通すのが基本です。
出力側にも同値分割を使う
入力だけを見ていると、出力の分岐を見落とします。
たとえば「送料は、購入金額に応じて0円・300円・550円のいずれか」という仕様なら、出力が3クラスあることになります。入力金額の境界だけでなく、3種類の送料がすべて出ることを確認してください。
条件が複数絡む場合は、決定表テストで組み合わせを整理する方が確実です。
使うときの注意点
ケースを作りすぎない
同値分割の目的は「減らすこと」です。 同じクラスから2つも3つも値を選んでいるなら、クラスの切り方が間違っているか、減らす意図を忘れています。
境界の定義を間違えない
「100件まで表示」の境界は 100 と 101 です。0件と1件も境界です。 リストが空のときの表示は、実装漏れが非常に多い箇所です。
この技法だけでは足りない領域がある
同値分割と境界値分析が扱うのは「1つの入力項目の範囲」です。項目どうしの関係は別の技法の担当になります。
まとめ
- 同値分割でどこを見るか、境界値分析でどの値を入れるかを決める
- 境界値は2値(境界と外側の隣)で通常は十分。3値を使うかはチームで統一する
- 数値の境界だけで終わらせない。 空欄・全角数字・小数・前後の空白を必ず確認する
- 「1,000円以上」は1,000円を含む。税込か税抜かも仕様書に無いことが多い
- 文字数は絵文字と結合文字で数え方が変わる。テストケースを1本入れる
- 日付は月末・うるう年・年またぎ・タイムゾーンが境界
- 無効値は1ケースに1つだけ。 有効値は組み合わせてよい
- 入力だけでなく出力の同値クラスも分ける
- 0件・空リストの表示は境界。実装漏れが多い
この技法の本当の価値は、テスト実行ではなく仕様の穴を見つけることにあります。 上流工程での使い方はウォーターフォール開発におけるQAの重要性とテスト技法の活用法にまとめました。