テストケースとは、ソフトウェアが正しく動作するかを確認するための「検証手順書」です。本記事では、テストケースの書き方・作成方法・実務で使える設計のコツを実例つきで解説します。「何を書けばよいかわからない」「正常系しか思いつかない」「人によって内容がバラバラになる」といった悩みをお持ちの方にも参考にしていただける内容です。
「なんとなく試してみる」テストと、テストケースに基づいた設計テストでは、バグ検出率もチーム間の再現性もまったく異なります。テストケースの書き方を押さえることが、品質保証の入口です。
📌 この記事はこんな方におすすめ
- テストケースの書き方を基礎から学びたいQAエンジニア・開発者
- 「何をどこまで書けばいいか」迷っている方
- テストケースが属人的になっていて、チームで共有しにくい方
- 自動テスト(pytest)にテストケース設計を活かしたい方
✅ この記事を読むと得られること
- テストケースの構成要素と書き方の基本がわかる
- 良いテストケース・悪いテストケースの違いを具体例で理解できる
- 正常系・異常系・境界値の分類と実務での使い方がわかる
👤 この記事を書いた人
QAエンジニア・テスト自動化エンジニアとして15年以上の実務経験を持つ Yoshi が執筆。テストケース設計はWeb系・組み込み系・金融系など複数ドメインで実践してきたテーマです。
📌 結論
- テストケースとは「前提条件・操作手順・期待結果」を1セットにまとめた検証単位
- 良いテストケースは「誰が実行しても同じ結果が得られる」再現性が重要
- 正常系・異常系・境界値の3分類を意識して作成することで、網羅性が高まる
テストを実施するとき、「どこから手をつければいいかわからない」「テストした内容が人によってバラバラ」「同じバグを何度も見逃す」といった問題は、多くの現場で起きています。
こうした問題の根本にある原因のひとつが、テストケースの設計が曖昧なことです。テストケースを正しく書けるようになると、バグの見逃しが減り、チームでのレビューもしやすくなります。
テストケースとは?定義と役割
テストケースとは、「特定の条件下でソフトウェアの動作を検証するための、手順と期待結果を定義した文書」です。
簡単に言い換えると、次のような問いに答えるセットです。
| 問い | テストケース上での表現 |
|---|---|
| 何を確認するのか | テスト対象・テスト名 |
| どんな状態から始めるのか | 前提条件 |
| どんな操作をするのか | 操作手順 |
| 何が起きれば合格か | 期待結果 |
テストケースがあることで、次のような効果が期待できます。
- 誰が実行しても同じ内容をテストできる(再現性)
- 何をテストしたか・していないかが明確になる(追跡可能性)
- バグが再発したとき、どのテストが漏れていたかを特定しやすくなる
- 新しいメンバーが参加してもすぐにテストを引き継げる
テストケースの構成要素
テストケースに含める項目はプロジェクトやツールによって異なります。以下が基本構成です。
| 項目 | 内容 | 記入例 |
|---|---|---|
| テストID | 一意に識別するID | TC-LOGIN-001 |
| テスト名 | 何を確認するかを一言で | 正常系_有効な認証情報でログインできること |
| 前提条件 | テスト開始時の状態 | テストユーザー(test@example.com)が登録済みであること |
| 操作手順 | ステップごとの操作を番号で記述 | ①メールアドレスを入力 ②パスワードを入力 ③ログインボタンをクリック |
| 期待結果 | 操作後に起きるべき動作 | ダッシュボード画面(/dashboard)へ遷移する |
| 優先度 | テスト実行の優先順位 | 高 / 中 / 低 |
規模の大きいプロジェクトでは以下の項目が加わることもあります。
| 追加項目(任意) | 用途 |
|---|---|
| 入力データ | パラメータが複数ある場合に別列で管理する |
| テストタイプ | 機能テスト / 回帰テスト / 探索的テスト などの分類 |
| トレーサビリティ | 対応する要件ID・チケット番号を紐づける(例:REQ-042) |
| 実行結果 / 実行日 | Pass / Fail の記録と実施日 |
テストケース管理ツール早見表
管理ツールの選択は、チームの規模や運用スタイルによって変わります。
| ツール | 小規模チーム | 大規模チーム | 特徴 |
|---|---|---|---|
| Excel / Google Sheets | ◎ | △ | 導入コストゼロ・自由度が高い。大規模になると管理が煩雑になりやすい |
| TestRail | ○ | ◎ | 実行・レポート・Jira連携が充実。チームや案件をまたいだ管理に向く |
| Notion / Confluence | ◎ | ○ | ドキュメントと一元管理できる。テスト専用機能は限定的 |
テストケースの作成手順
テストケースを作成する際には、以下の手順を踏むと、漏れや重複を防ぎやすくなります。
| ① 仕様確認 |
| ↓ |
| ② テスト観点の抽出 |
| ↓ |
| ③ 正常系・異常系・境界値に分類 |
| ↓ |
| ④ テストケース作成 |
| ↓ |
| ⑤ レビュー |
| ↓ |
| ⑥ 実行・記録・更新 |
ステップ1:テスト対象の仕様を把握する
まず仕様書・要件定義書・受け入れ条件(ACs)を読み込みます。「どんな入力に対して、何が起きるべきか」の条件を洗い出すことが出発点です。仕様が曖昧な箇所は、テストケースを書く前に開発者や PO に確認しておくと、手戻りを防げます。
ステップ2:テストすべきパターンを分類する
仕様から、テストすべきパターンを「正常系・異常系・境界値」の3つに分類します(詳細は後述)。この分類があると、テストケースの抜け漏れを見つけやすくなります。
ステップ3:テストケースを書く
分類したパターンごとに、「前提条件・操作手順・期待結果」を具体的に記述します。このとき、1テストケース=1確認ポイントの原則を守ることが重要です。複数の確認を1つにまとめると、どこでFailしたか特定しにくくなります。
ステップ4:レビューを受ける
作成したテストケースは自己チェックだけでなく、別の人にレビューしてもらうと抜け漏れを発見しやすくなります。「この手順で本当に再現できるか」「期待結果は具体的か」の2点を中心に確認してもらいましょう。
ステップ5:実行・結果を記録し、必要に応じて更新する
テストケースは作って終わりではなく、実行結果(Pass/Fail)を記録し、仕様変更があれば更新します。古くなったテストケースは「テストした気になるだけ」で、実際には品質を担保できていないことがあるため注意が必要です。
テストケースの書き方【良い例・悪い例】
同じ「ログイン機能のテスト」でも、書き方によって品質が大きく変わります。
❌ 悪いテストケースの例
| 項目 | 記載内容 |
|---|---|
| テストID | TC-01 |
| テスト名 | ログインテスト |
| 前提条件 | (なし) |
| 操作手順 | ログインする |
| 期待結果 | ログインできる |
問題点:
- 「ログインする」という手順では、何を入力するのか他の人が再現できない
- 「ログインできる」では、どの画面に遷移すれば合格なのか判断できない
- 前提条件がないため、テストユーザーが存在しない環境では実行できない
✅ 良いテストケースの例
| 項目 | 記載内容 |
|---|---|
| テストID | TC-LOGIN-001 |
| テスト名 | 正常系_有効な認証情報でログインできること |
| 前提条件 | テストユーザー(test@example.com / Password123)が登録済みであること |
| 操作手順 | ①ログイン画面(/login)を開く ②メールアドレス欄に「test@example.com」を入力する ③パスワード欄に「Password123」を入力する ④「ログイン」ボタンをクリックする |
| 期待結果 | ダッシュボード画面(/dashboard)へ遷移し、「ようこそ、テストユーザー様」と表示される |
| 優先度 | 高 |
改善ポイント:
- テスト名に「正常系」と分類を明記し、テストの意図が一目でわかる
- 前提条件に具体的なユーザー情報を記載し、誰でも再現できる
- 操作手順を番号で細分化し、どのステップでFailしたか特定しやすい
- 期待結果に「遷移先URL」と「表示テキスト」を具体的に書き、判定基準が明確
正常系・異常系・境界値の分類
テストケースを作成するとき、「正常系・異常系・境界値」の3つに分類して考えると、網羅性が高まります。
| 分類 | 概要 | ログイン機能の例 |
|---|---|---|
| ✅ 正常系 | 正しい入力・正しい操作で、期待通りに動作すること | 有効なID・パスワードでログインできる |
| ❌ 異常系 | 不正な入力・操作に対して、適切にエラーを返すこと | パスワード誤り・空欄・存在しないIDでエラーが表示される |
| ⚠️ 境界値 | 有効・無効の境界付近の値でバグを検出する | 仕様が「8〜20文字」なら 7文字(無効)・8文字(有効)・20文字(有効)・21文字(無効)の4点が基本 |
7(下限を1つ外れる)・8(下限境界)・20(上限境界)・21(上限を1つ外れる)をテストします。Off-by-oneエラー(>= と > の混同など)は境界値でしか発見できないことが多いです。テストケース作成でよくある失敗パターン
15年以上の現場経験で繰り返し見てきた失敗を4つ紹介します。
① 期待結果が曖昧で判定できない
「正常に動く」「エラーが出ない」のような期待結果は、実際にテストしても Pass/Fail を判定できません。「○○画面が表示される」「○○のエラーメッセージが表示される」のように、具体的な状態を書きましょう。
② 1つのテストケースに複数の確認を詰め込む
「ログインして、プロフィールを編集して、ログアウトする」を1テストケースにまとめると、途中でFailしたときに原因の特定が難しくなります。確認ポイントを1つずつに分割することで、問題箇所の特定が容易になります。
③ 前提条件を書かず、再現できないテストになる
「特定のユーザーでないと再現しない」「事前にデータを登録しておく必要がある」という条件を書き忘れると、別の環境や別の担当者が実行したときに再現できません。テストの開始状態を明示することが重要です。
④ 正常系だけ書いて異常系・境界値を後回しにする
「動くことだけ確認した」という状態は、バグの大半が潜む異常系・境界値を見逃しています。実務では「時間がないから正常系だけ」が積み重なって、リリース後にバグが露見するケースが少なくありません。異常系は最初から設計に組み込む習慣をつけましょう。
自動テスト(pytest)へのテストケース適用
この章のサンプルコードはGitHubでも公開しています:github.com/YOSHITSUGU728/automated-testing-portfolio
テストケースから自動テストまでの流れ
テストケースは設計で終わりではなく、pytestに落とし込むことで自動テストとして継続的に活用できます。
| ① 仕様確認 | → | ② テスト設計 | → | ③ テストケース作成 | → | ④ pytest 実装 | → | ⑤ CI/CD 実行 |
| 要件・仕様書を読む | 同値分割・境界値分析 | 正常系・異常系・境界値 | parametrize に変換 | GitHub Actions など |
pytest parametrize でテストケース表をコード化する
作成したテストケース一覧は、pytestの @pytest.mark.parametrize を使ってそのままコード化できます。ここではログインフォームの入力バリデーション関数を例に、テストケース表とコードの対応を示します。
import pytest
def validate_login_form(email: str, password: str) -> dict:
"""ログインフォームの入力バリデーション(形式・文字数チェックのみ)
※ 実際の認証処理(DB照合・セッション発行)は行わない。
入力値の形式チェックを行うユーティリティ関数。
"""
if not email or not password:
return {"success": False, "message": "メールアドレスとパスワードを入力してください"}
if "@" not in email:
return {"success": False, "message": "メールアドレスの形式が正しくありません"}
if len(password) < 8:
return {"success": False, "message": "パスワードは8文字以上で入力してください"}
return {"success": True, "message": "入力値は有効です"}
# テストケース一覧をそのままパラメータに変換
@pytest.mark.parametrize("test_id, email, password, expected_success, expected_message", [
# 正常系(有効な入力形式)
("TC-FORM-001", "test@example.com", "Password123", True, "入力値は有効です"),
# 異常系:空欄
("TC-FORM-002", "", "Password123", False, "メールアドレスとパスワードを入力してください"),
("TC-FORM-003", "test@example.com", "", False, "メールアドレスとパスワードを入力してください"),
# 異常系:メール形式不正
("TC-FORM-004", "invalid-email", "Password123", False, "メールアドレスの形式が正しくありません"),
# 境界値:パスワード文字数(仕様:8文字以上)
("TC-FORM-005", "test@example.com", "Pass123", False, "パスワードは8文字以上で入力してください"), # 7文字(下限-1)
("TC-FORM-006", "test@example.com", "Pass1234", True, "入力値は有効です"), # 8文字(下限境界値)
])
def test_login_form_validation(test_id: str, email: str, password: str,
expected_success: bool, expected_message: str) -> None:
result = validate_login_form(email, password)
assert result["success"] == expected_success, f"[{test_id}] success の期待値が異なります"
assert result["message"] == expected_message, f"[{test_id}] message の期待値が異なります"📖 関連記事
FAQ
Q. テストケースとテスト仕様書の違いは何ですか?
テスト仕様書はテストの全体方針・範囲・戦略をまとめた上位文書です。テストケースはその中の個々の検証手順を定義したものです。規模の大きいプロジェクトでは「テスト計画書 → テスト仕様書 → テストケース」という階層構造になることが多いです。
Q. テストケースはどこまで細かく書けばいいですか?
「別の人が手順を読んで、同じ操作を再現できるレベル」が基本的な目安です。チーム全員が同じ機能を熟知している場合は省略できる記述もありますが、新メンバーや引き継ぎを考慮すると、ある程度具体的に書いておくほうが長期的にはメンテナンスコストを下げられます。
Q. テストケースの数はどれくらいが適切ですか?
「多ければ安心」ではありません。同値分割や境界値分析などの設計技法を使い、代表値に絞り込むことが重要です。テストケースが多すぎると、実行・メンテナンスのコストが増え、かえって重要なテストが埋もれてしまうリスクがあります。重要機能ほどケース数は増える傾向がありますが、まずは主要な正常系・異常系・境界値を網羅することを優先し、そこから必要に応じて追加するアプローチが実務では扱いやすいです。
Q. テストケースを自動テストに変換する基準は?
繰り返し実行するもの・回帰テストとして毎回確認するものは自動化の候補です。一方で、「初回だけ確認する」「UIの見た目を目視確認する」ようなケースは手動テストのほうが向いていることがあります。すべてを自動化する必要はなく、コストと効果を見比べて判断しましょう。
Q. 仕様書がないプロジェクトでのテストケース作成はどうすればいいですか?
仕様書がない場合は、既存の動作を「事実上の仕様」としてテストケースに書き起こすアプローチが有効です。開発者へのヒアリングや探索的テストで動作を把握しながら、テストケースを徐々に整備していく方法が現場ではよく使われています。
📋 まとめ
- テストケースとは「前提条件・操作手順・期待結果」を1セットにした検証単位。再現性と追跡可能性が重要
- 良いテストケースは、誰が読んでも同じ操作を再現でき、期待結果が具体的で判定できる状態になっている
- 正常系・異常系・境界値の3分類を意識することで、漏れのないテストケース設計ができる
- pytestのparametrizeと組み合わせると、テストケース一覧をそのまま自動テストに変換できる
テストケースの品質は、そのままテスト全体の品質に直結します。まずは身近な機能(ログイン・フォームバリデーションなど)のテストケースを一度書いてみることで、設計の感覚が身についていきます。テストケースがある状態とない状態では、チームのレビュー効率とバグ検出率が大きく変わることを実感できるはずです。
