ドキュメント / 詳細設計 / その他•PART 03 / 03•2026.06.18•20 min read
PART 03 — 単体テスト仕様書
テスト設計の体系と自動化
単体テスト仕様書は実装前に「何をどうテストするか」を定義する設計書だ。テスト観点・境界値分析・pytest による実装例を通じて品質を作り込む方法を解説する。
詳細設計単体テストpytest境界値分析Python
単体テスト仕様書の位置づけ
単体テスト仕様書は「各クラス・メソッドが単独で正しく動作することを検証するテストの設計書」だ。詳細設計のメソッド定義・業務ロジック定義を受けて、どのケースを検証するかを事前に定義する。
💡 テスト仕様書を先に書く
テスト仕様書を実装前に作成することで設計の曖昧さが明確になる。「このメソッドを NULL で呼んだら何を返す?」という問いに答えられない設計は不完全だ。
テスト対象スコープ
| 対象 | 内容 |
| テスト対象クラス | OrderService, StockService, OrderValidator |
| テスト対象メソッド | 各クラスの public メソッド全て |
| テスト除外 | private メソッド(public 経由でテスト)、DTO(ゲッター/セッターのみ) |
| モック対象 | Repository(DB)、外部サービス呼び出し、メールサービス |
| カバレッジ目標 | 行カバレッジ 80%以上、分岐カバレッジ 70%以上 |
テスト観点
| 観点 | 確認内容 |
| 正常系 | 正しい入力で期待値が返るか |
| 境界値 | 最小値・最大値・その前後で正しく動作するか |
| 異常系(入力値) | NULL・空文字・型違い・範囲外の値を渡したときの挙動 |
| 異常系(依存) | 依存するサービス・DBがエラーを返したときの挙動 |
| 業務ロジック | コード値・フラグによる分岐が正しく動作するか |
テストケース設計
| テストID | 対象メソッド | 分類 | 入力 | 期待結果 |
| UT-OS-001 | OrderService.confirmOrder | 正常系 | 在庫あり商品・数量1 | 注文IDが返却される |
| UT-OS-002 | OrderService.confirmOrder | 異常系 | 在庫不足商品 | BizException(BIZ_001) がスローされる |
| UT-OS-003 | OrderService.confirmOrder | 境界値 | 在庫数 = 注文数(ちょうど) | 注文確定成功 |
| UT-OS-004 | OrderService.confirmOrder | 境界値 | 在庫数 = 注文数 - 1 | BizException(BIZ_001) がスローされる |
| UT-OS-005 | OrderService.confirmOrder | 異常系 | userId = null | ValueError がスローされる |
| UT-OS-006 | OrderService.cancelOrder | 正常系 | 確認済み注文・本人操作 | キャンセル成功 |
| UT-OS-007 | OrderService.cancelOrder | 異常系 | 出荷済み注文 | BizException(BIZ_002) がスローされる |
境界値・同値分割
対象: OrderValidator.validateQuantity(quantity: int)
仕様: 数量は 1以上 9999以下の整数
同値クラス分割:
有効クラス : 1 ~ 9999
無効クラスA : 0以下
無効クラスB : 10000以上
無効クラスC : NULL
境界値テストケース:
ID | 入力 | 期待
--------|--------|---------------------
BV-Q-01 | -1 | ValidationException
BV-Q-02 | 0 | ValidationException(境界)
BV-Q-03 | 1 | OK(境界)
BV-Q-04 | 5000 | OK(代表値)
BV-Q-05 | 9999 | OK(境界)
BV-Q-06 | 10000 | ValidationException(境界)
BV-Q-07 | NULL | ValidationException
テスト仕様書の構成
| セクション | 内容 |
| 1. テスト計画 | 対象クラス・テスト環境・カバレッジ目標・実施期間 |
| 2. テスト観点一覧 | 観点ごとの確認内容・優先度 |
| 3. テストケース一覧 | テストID・分類・入力・期待結果・実施結果 |
| 4. テストデータ | 使用するテストデータの定義・初期化方法 |
| 5. モック定義 | モック対象・スタブの戻り値 |
| 6. 実施結果 | 合否・バグID・修正状況 |
Python Tips — pytest でのテスト実装
Python — pytest によるテスト仕様書の実装例
"""
pytest によるテスト仕様書の実装例
pip install pytest
"""
import pytest
from unittest.mock import MagicMock
class BizException(Exception):
def __init__(self, code):
self.code = code
class OrderService:
def __init__(self, order_repo, stock_service):
self.order_repo = order_repo
self.stock_service = stock_service
def confirm_order(self, user_id, product_id, quantity):
if user_id is None:
raise ValueError("user_id は必須です")
available = self.stock_service.check_stock(product_id)
if available < quantity:
raise BizException("BIZ_001")
order = self.order_repo.save(user_id, product_id, quantity)
return order["order_id"]
class TestOrderServiceConfirmOrder:
@pytest.fixture
def service(self):
repo = MagicMock()
stock = MagicMock()
repo.save.return_value = {"order_id": 12345}
return OrderService(repo, stock), repo, stock
def test_UT_OS_001_正常系(self, service):
svc, repo, stock = service
stock.check_stock.return_value = 10
result = svc.confirm_order(user_id=1, product_id=100, quantity=1)
assert result == 12345
def test_UT_OS_002_在庫不足(self, service):
svc, repo, stock = service
stock.check_stock.return_value = 0
with pytest.raises(BizException) as exc:
svc.confirm_order(user_id=1, product_id=100, quantity=1)
assert exc.value.code == "BIZ_001"
@pytest.mark.parametrize("stock_qty,order_qty,ok", [
(5, 5, True), # UT-OS-003: 在庫 = 注文数
(4, 5, False), # UT-OS-004: 在庫不足
])
def test_UT_OS_境界値(self, service, stock_qty, order_qty, ok):
svc, repo, stock = service
stock.check_stock.return_value = stock_qty
if ok:
assert svc.confirm_order(1, 100, order_qty) == 12345
else:
with pytest.raises(BizException):
svc.confirm_order(1, 100, order_qty)
def test_UT_OS_005_userId_null(self, service):
svc, _, _ = service
with pytest.raises(ValueError, match="user_id は必須です"):
svc.confirm_order(user_id=None, product_id=100, quantity=1)
レビューチェックリスト
| # | チェック項目 |
| 1 | 全 public メソッドにテストケースが設計されているか |
| 2 | 正常系・異常系・境界値がすべて網羅されているか |
| 3 | NULL・空入力のケースが含まれているか |
| 4 | 依存クラスが適切にモック化されているか |
| 5 | カバレッジ目標が定義されているか |
| 6 | テストケースIDが設計書と対応しているか |