テスト設計の基礎である「境界値分析」と「同値分割」は、QAエンジニアが最初に習得すべき技法です。この2つを使いこなすことで、テストケース数を最小限に抑えながら、バグが潜みやすい箇所を効率よく検出できます。
境界値分析・同値分割を正しく使うと、「全パターンをテストしたい」という衝動を抑えながら、バグが最も起きやすい箇所に集中してテストできるようになります。
📌 この記事はこんな方におすすめ
- テスト設計の基礎を体系的に学びたいQAエンジニア・開発者
- 「どこまでテストすればいいか」で迷っている方
- テストケースが多すぎて管理しきれなくなっている方
- 自動テストの設計に境界値・同値分割を活かしたい方
✅ この記事を読むと得られること
- 同値分割・境界値分析の考え方と使い方がわかる
- テストケースを削減しながら品質を保つ設計ができるようになる
- 実務でよく出るフォームバリデーションへの適用方法がわかる
👤 この記事を書いた人
QAエンジニア・テスト自動化エンジニアとして15年以上の実務経験を持つ Yoshi が執筆。境界値分析・同値分割は実際のプロジェクトで毎日使う基本技法であり、自動テストの設計にも直結する知識です。実装コードはGitHubで公開中:github.com/YOSHITSUGU728/automated-testing-portfolio
📌 結論
- 同値分割:同じ動作をするデータをグループ化し、代表値1つでテストする
- 境界値分析:グループの境界(端)の値を重点的にテストする
- この2つを組み合わせることで、少ないテストケースで高いバグ検出率を実現できる
「全部のパターンをテストしなければ」と思うと、テストケースは際限なく増えていきます。しかし現実には時間もリソースも有限です。テスト設計の技法を使うと、次のような問題を解決できます。
- テストケースが膨大になり管理できない
- 何をテストすれば十分なのかわからない
- バグが出やすい箇所を見逃してしまう
この記事では、QAの現場で最も使われる2つの基本技法「同値分割」と「境界値分析」を、具体例を交えながらわかりやすく解説します。
テスト設計技法とは?なぜ必要か
テスト設計技法とは、「どの値をテストすれば、少ないテスト数でバグを効率よく見つけられるか」を体系化したアプローチです。
例えば年齢入力フィールド(1〜120歳)をテストする場合、1から120まで全部試せば確実ですが、現実的ではありません。テスト設計技法を使うと、同じ信頼性を保ちながらテスト数を大幅に削減できます。
テスト設計なしで起きる問題:
- テストケース数が無限に膨らむ
- 何をテストしたか・していないかが曖昧になる
- バグが出やすい「境界」を見逃す
- 時間切れで重要なテストが実行できない
- 人によってテスト内容がバラバラになる
| 比較項目 | 設計技法なし | 設計技法あり |
|---|---|---|
| テストケース数 | 膨大・管理困難 | 最小限・整理された状態 |
| バグ検出効率 | 漏れが多い | 重要箇所を網羅できる |
| チームでの共有 | 属人的・バラバラ | 再現性があり共有しやすい |
| 自動化との相性 | テスト数が多く重くなる | parametrize と組み合わせやすい |
① 同値分割(Equivalence Partitioning)
同値分割とは、「同じ動作をすると期待されるデータをグループ(同値クラス)に分け、各グループから代表値を1つだけテストする」技法です。
グループ内のどの値も同じ結果になると仮定するため、グループ全体を1つの値で代表できます。
具体例:年齢入力フィールド(有効範囲:1〜120歳)
| 同値クラス | 値の範囲 | 代表値(例) | 期待結果 |
|---|---|---|---|
| ✅ 有効クラス | 1 〜 120 | 50 | 正常に受け付ける |
| ❌ 無効クラス① | 0以下 | -1 または 0 | エラーメッセージを表示 |
| ❌ 無効クラス② | 121以上 | 121 または 200 | エラーメッセージを表示 |
| ❌ 無効クラス③ | 数値以外 | “abc” や 空文字 | エラーメッセージを表示 |
同値分割のコツ
同値クラスを見つけるには、仕様書の条件に注目します。
| 仕様の条件 | 有効クラス | 無効クラス |
|---|---|---|
| 1〜120の整数 | 1〜120の整数 | 0以下 / 121以上 / 小数 / 文字列 |
| パスワード8〜20文字 | 8〜20文字の文字列 | 7文字以下 / 21文字以上 / 空文字 |
| メールアドレス形式 | xxx@xxx.xxx 形式 | @なし / ドメインなし / 空文字 |
② 境界値分析(Boundary Value Analysis)
境界値分析とは、「同値クラスの境界(端)の値を重点的にテストする」技法です。バグは境界付近で最も多く発生することが統計的に知られており、同値分割と組み合わせることで非常に高い効果を発揮します。境界付近では条件分岐(>=・<= など)のミスが起きやすく、開発者が想定していない値が入りやすいためです。
なぜ境界でバグが起きやすいのか?
開発者がよく犯すミスの典型例です。
| よくあるミス | 誤ったコード例 | 正しいコード例 |
|---|---|---|
| Off-by-one エラー | if age > 1 and age < 120 | if age >= 1 and age <= 120 |
| 不等号の向き間違い | if length < 8(8文字でエラー) | if length <= 8(8文字はOK) |
境界値の選び方(3点法)
境界値分析では各境界について「境界の1つ手前」「境界値そのもの」「境界の1つ先」の3点をテストします。
| 境界 | 境界値 -1 | 境界値 | 境界値 +1 |
|---|---|---|---|
| 下限(1) | 0 ❌ 無効 | 1 ✅ 有効 | 2 ✅ 有効 |
| 上限(120) | 119 ✅ 有効 | 120 ✅ 有効 | 121 ❌ 無効 |
③ 同値分割 × 境界値分析の組み合わせ
実務では2つの技法を組み合わせて使います。同値分割でグループを整理し、境界値分析で各グループの端を重点テストするのが基本パターンです。
実例:パスワード文字数バリデーション(8〜20文字)
| テストケース | 値 | 分類 | 期待結果 |
|---|---|---|---|
| TC-01 | 7文字 | 下限境界値 -1(無効) | ❌ エラー |
| TC-02 | 8文字 | 下限境界値(有効) | ✅ 正常 |
| TC-03 | 9文字 | 下限境界値 +1(有効) | ✅ 正常 |
| TC-04 | 14文字 | 有効クラス代表値(同値分割) | ✅ 正常 |
| TC-05 | 19文字 | 上限境界値 -1(有効) | ✅ 正常 |
| TC-06 | 20文字 | 上限境界値(有効) | ✅ 正常 |
| TC-07 | 21文字 | 上限境界値 +1(無効) | ❌ エラー |
| TC-08 | 0文字(空) | 無効クラス代表値(同値分割) | ❌ エラー |
この8件のテストケースで、パスワードバリデーションのほぼすべての重要パターンを網羅できます。むやみに増やすよりも、この8件を確実に実行するほうが品質は高まります。
④ 自動テスト(pytest parametrize)への応用
同値分割・境界値分析で設計したテストケースは、pytestの @pytest.mark.parametrize と相性が抜群です。表で整理した値をそのままパラメータとして渡せます。
import pytest
def validate_password_length(password: str) -> bool:
"""パスワードが8〜20文字かどうかを検証する"""
return 8 <= len(password) <= 20
# 同値分割 × 境界値分析 をそのままパラメータ化
@pytest.mark.parametrize("password, expected", [
# 境界値(下限)
("a" * 7, False), # TC-01: 7文字 → 無効
("a" * 8, True), # TC-02: 8文字 → 有効(下限境界値)
("a" * 9, True), # TC-03: 9文字 → 有効
# 有効クラス代表値(同値分割)
("a" * 14, True), # TC-04: 14文字 → 有効
# 境界値(上限)
("a" * 19, True), # TC-05: 19文字 → 有効
("a" * 20, True), # TC-06: 20文字 → 有効(上限境界値)
("a" * 21, False), # TC-07: 21文字 → 無効
# 無効クラス代表値(同値分割)
("", False), # TC-08: 空文字 → 無効
])
def test_password_validation(password, expected):
assert validate_password_length(password) == expected⑤ テスト設計でよくある失敗パターン
同値分割・境界値分析を学んでも、実務では次のような失敗をしがちです。事前に把握しておくことで、設計の精度が大幅に上がります。
① 境界値だけテストして同値クラスを作らない
境界値(1・2・119・120・121 など)だけをテストして終わりにしてしまうケースです。同値クラスがないと「数値以外の入力(文字列・空文字など)」の無効クラスが漏れます。必ず同値分割でクラスを整理してから境界値を選ぶ順番を守りましょう。
② 有効クラスをテストせず、異常系だけ確認する
「エラーが出ないこと」だけ確認して「正常に動作すること」をテストしないパターンです。有効クラスの代表値テスト(正常系)を省くと、正常な入力で正しい処理が行われているかが確認できません。正常系・異常系の両方が必須です。
③ 仕様書の条件を見ずに「なんとなく」テストケースを作る
「なんとなく5・10・100を試しておこう」という感覚的なテストは、設計技法の真逆です。同値クラスは必ず仕様書の条件(「1〜120」「8〜20文字」など)から導き出します。仕様が曖昧な場合は、まず仕様を明確にすることが先決です。
④ 境界値を1つしかテストしない
「上限は120だから120だけテストすればいい」と思いがちですが、境界値分析の要点は「境界の前後」を含めた複数点を確認することです。120のみのテストでは「121が正しくエラーになるか」「119が正しく通るか」が検証できません。最低でも境界値と、その外側1点の2点をテストしましょう。
FAQ
Q. 同値分割と境界値分析、どちらを先にやるべきですか?
必ず同値分割を先に行います。まずグループ(同値クラス)を特定し、各グループの境界を境界値分析でテストするのが正しい順序です。境界値はグループがないと定義できないので、同値分割が土台になります。
Q. 有効クラスのテストも必要ですか?無効クラスだけではダメですか?
両方必要です。有効クラスのテスト(正常系)は「正しい入力で正しく動作すること」を確認します。無効クラスのテスト(異常系)は「不正な入力を適切に弾けること」を確認します。どちらか一方だけでは品質を担保できません。
Q. 境界値は必ず「 -1 / 境界値 / +1 」の3点テストするべきですか?
時間に余裕があれば3点法が理想ですが、最低限「境界値そのもの」と「その外側1つ」の2点は必ずテストしてください。実務では優先度の高いテストから3点法を適用し、優先度が低いものは2点法に簡略化することもよくあります。
Q. これらの技法は手動テストだけでなく自動テストでも使えますか?
むしろ自動テストと非常に相性がよい技法です。pytestの @pytest.mark.parametrize を使うと、同値分割・境界値分析で設計したテストケース一覧をそのままパラメータとして渡せます。設計と実装が直結するため、テストの意図がコードから読み取れる状態になります。
📖 関連記事
📋 この記事のまとめ
- 同値分割:同じ動作をする値をグループ化し、代表値1つでテストすることでケース数を削減できる
- 境界値分析:グループの端(境界)の値を重点テストすることで、Off-by-oneエラーなどを効率よく発見できる
- 組み合わせが基本:同値分割でグループを定義し、境界値分析で各境界を3点テストするのが実務での標準パターン
- pytestとの相性◎:
@pytest.mark.parametrizeを使うと設計したテストケース表をそのままコードに変換できる
「全パターンをテストしなければ」というプレッシャーから解放されるのが、テスト設計技法を学ぶ最大のメリットです。同値分割と境界値分析を使えば、少ないテストケースで高い信頼性を実現できます。まずは身近なフォームバリデーションに適用してみましょう。
