テスト初心者脱出講座 | [第2回]: テストケースとその書き方

 

## 1. はじめに 〜「とりあえず動いた」で終わらせないために〜

開発がひと段落して、ふと先輩から言われた一言。

> 「テストケース、ちゃんと書いた？」

プログラムは動いてるし、手動で確認したし、エラーも出ないし……と思ったあなた。それ、**危険信号**です！

テストは「壊れてない」ことを証明する唯一の手段であり、将来の自分や他人への**技術的な安心**でもあります。この記事では、特に初心者がつまずきやすい「テストケースの書き方」を、実例コード付きで丁寧に解説していきます。

---

## 2. テストケースとは？〜単なる“確認項目リスト”ではない〜

### ✅ 定義

\*\*テストケース（Test Case）\*\*とは、「ある入力に対して、期待される出力（もしくは挙動）を検証するための条件や手順の集合」です。

| 項目   | 内容                 |
| ---- | ------------------ |
| 入力   | テスト対象に与える値         |
| 期待結果 | どう動くべきか（正しく動作すれば◯） |
| 実行手順 | どこをどう操作するか         |
| 前提条件 | テストの実行前に整えておく環境や状態 |

### 🔍 テスト仕様書との違い

* **テスト仕様書**：複数のテストケースをまとめたもの
* **テストケース**：仕様書内の個々のテストシナリオ

---

## 3. 実例で学ぶ：テストケースの書き方

今回は、Pythonで作成したシンプルなユーザー登録関数を題材にします。

### 🧩 サンプル関数

```python
def register_user(username: str, email: str) -> dict:
    if not username or not email:
        raise ValueError("Username and email are required.")
    if "@" not in email:
        raise ValueError("Invalid email format.")
    return {"username": username, "email": email}
```

### 🧪 テストケース例（Pytest形式）

```python
import pytest
from user_service import register_user

def test_register_user_valid_input():
    result = register_user("alice", "alice@example.com")
    assert result == {"username": "alice", "email": "alice@example.com"}

def test_register_user_missing_username():
    with pytest.raises(ValueError, match="required"):
        register_user("", "alice@example.com")

def test_register_user_invalid_email():
    with pytest.raises(ValueError, match="Invalid email format"):
        register_user("alice", "alice[at]example.com")
```

### 💡 テストケース設計のコツ

* **正常系と異常系**を必ず分けて書く
* エラーは**メッセージまで確認**（単なる例外発生だけでなく）
* 必須パラメータが**空文字やNone**のときの動作も確認

---

## 4. 実務で使える！書き方のポイントと落とし穴

### ✅ よくある落とし穴

| 落とし穴                  | 対策                                                         |
| --------------------- | ---------------------------------------------------------- |
| ケース名が不明瞭（例：`test1()`） | **何をテストしているか明示的に書く（例：`test_register_user_valid_input()`）** |
| 入力パターンが偏る             | 境界値（例：最大長、空文字、特殊文字）を網羅                                     |
| 結果しか見てない              | 途中の状態やログ出力なども確認対象にすること                                     |

### 🛠 実務Tip

* **パラメータ化**を使えば、似たようなパターンを一括で書ける

```python
import pytest

@pytest.mark.parametrize("username,email", [
    ("", "user@example.com"),
    ("user", ""),
    ("user", "invalid-email"),
])
def test_register_user_invalid_inputs(username, email):
    with pytest.raises(ValueError):
        register_user(username, email)
```

* **テスト対象のコードに手を加えることを恐れない**
  → テストしやすい構造（Pure関数、DIなど）に変えていくのも一つの成長！

---

## 5. 応用：業務でテストケースを運用するには？

### 🗂 管理方法

* **Excel or Google Sheets**：非エンジニア含むチーム向け
* **TestRail, PractiTest**：大規模・複雑プロジェクト向け
* **コード内コメント or テスト関数名**：小規模チーム向け（アジャイル）

### 🔁 自動テストとの連携

* CI/CD（GitHub Actions, CircleCIなど）で毎回実行
* テストカバレッジも可視化して、**やってるつもり**から卒業

---

## 6. まとめ：テストケースを書く意味と未来

### ✅ メリット

* バグの早期発見
* リファクタリング時の安心材料
* チーム内での「暗黙知→形式知」化

### ⚠ デメリット

* 初期コスト（書くのが面倒に感じる）
* 書き方のルール統一が難しい

### 🌱 今後の展望

* 自動生成ツール（AI）との併用
* テスト駆動開発（TDD）へのシフト

---

## 🚀 おわりに：テストは“保険”じゃなく“未来への投資”

テストケースを書くことは、「動けばいい」開発から「壊れにくい」開発へと進化する第一歩です。この記事が、あなたの**テスト初心者脱出**のきっかけとなれば幸いです！

---

## 💬 参考リンク

* [pytest公式ドキュメント](https://docs.pytest.org/)
* [TDD入門（Qiita記事）](https://qiita.com/tags/tdd)

---

✍️ **次回予告：「テストケースとその書き方」もお楽しみに！**

---