概要
バグの多くは**境界条件(境界値)**で発生する。
1未満、100超、0の扱い、空配列、最大件数…。
TDDではこのような「壊れやすい瞬間」を**“仕様として先にテストに刻む”**ことで、
未然に不具合を防ぎ、堅牢で進化可能な設計を実現できる。
本稿では、Python + pytest による実装を通じて、
TDDにおける境界条件設計の技術と思想を実践的に解説する。
1. 境界条件とは「コードの不確実性が最も高まる瞬間」
- 「>= 100」と「> 100」の違い
- 配列長が
0
、1
、最大
のときの処理 - 入力が空文字列、null、0 のとき…
✔️ テストがなければ、実装者の感覚頼りになる
✔️ テストがあるなら、それが境界の仕様書になる
2. 実例:is_valid_age(age: int) -> bool
のTDD
🔴 Red – 仕様を先に定義する
# test_validator.py
from validator import is_valid_age
def test_age_under_minimum():
assert is_valid_age(-1) is False
def test_age_minimum():
assert is_valid_age(0) is True
def test_age_maximum():
assert is_valid_age(120) is True
def test_age_over_maximum():
assert is_valid_age(121) is False
- ここで 「何を許し、何を拒否するか」 が明確に仕様化される
- バグの種を先に潰す ための Red である
3. 🟢 Green – テストを通す実装を書く
# validator.py
def is_valid_age(age: int) -> bool:
return 0 <= age <= 120
- ✅ 単純な比較だが、仕様が先に定義されているから迷いがない
- ✅ 誰が見ても「何が有効な年齢か」が明らか
4. TDDにおける境界設計のパターン
テスト観点 | 例 | 理由 |
---|---|---|
最小値/最大値 |
0 , 120
|
許容される境界を明示 |
境界直下/直上 |
-1 , 121
|
排除される境界を明示 |
空/null/None |
"" , None
|
実行時エラーや意図しない通過を防止 |
最短/最長の配列 |
[] , ["a"] * 100
|
反復処理の開始点・終了点 |
5. テストに刻むべき“設計の綻び”
TDDで境界を仕様化するとは、「開発者の迷い」を先に潰すことである。
- 曖昧な値 → 明示的な仕様で定義
- 複雑な条件 → テストケースで分解
- 例外的な振る舞い → テストで「期待」として固定化
✔️ TDDで書いた境界テストは、**「将来の改修に対するバグガード」**になる
設計判断フロー
① この関数に「境界的な値」があるか? → YES → その境界をRedで書く
② 最小/最大/その前後はどうなるべきか? → YES → 明示的に仕様化
③ 許容する値と、拒否する値は? → 曖昧なら仕様として定義してしまう
④ 後続処理で依存していないか? → 境界を守ることで他ロジックを単純化できる
よくあるミスと対策
❌ 境界条件をあとでテストに追加しようとする
→ ✅ TDDでは最初に“失敗する境界”をRedとして書く
❌ 「たぶん動く」コードでテストを書かない
→ ✅ 曖昧な仕様こそ、最も先に書くべきテスト
❌ 境界テストが通るだけのコードで満足する
→ ✅ リファクタ後も壊れない保証として、Red → Green → Refactor を一貫させる
結語
境界条件とは、仕様の曖昧さが最も現れる地点であり、最も壊れやすい地点でもある。
TDDではその危うさを、Redとして先に可視化し、Greenとして仕様に昇華する。
- 開発者の不安をコード化する
- 境界をテストに刻むことで安心して構造を進化できる
- 境界値が明文化されていれば、バグは未然に潰される
TDDとは、
“不安をRedにし、安心をGreenで設計に変える。進化のための予防的戦略である。”