Knowledge Notebook
一覧に戻る

単体テスト・結合テスト・システムテスト・受け入れテストの違いとは?略称や実施タイミングを整理してみた

ソフトウェア開発の現場に携わると、日常的に「UT」「IT」「ST」「UAT」といったテスト用語やアルファベットの略称が飛び交います。しかし、案件やプロジェクトの文化によって「結合テストをITと呼ぶかPTと呼ぶか」「どこまでが単体テストでどこからが結合テストなのか」といった定義が曖昧で、戸惑った経験がある方も多いのではないでしょうか。

ソフトウェアテストは、成果物の品質を担保し、運用開始後の不具合リスクを下げるために欠かせない工程です。それぞれのテストフェーズが「何を」「誰が」「どのタイミングで」「どう検証するのか」を正しく整理しておくと、設計書の作成やスケジュール調整がスムーズになります。今回は各テストレベルの違いや略称に加えて、各フェーズで現場において使われる日本語のテストケース表現や仕様書サンプル、コード例をまとめました。

1. テストレベルの全体像と略称(UT・IT・ST・UAT)

システム開発におけるテストは、一般的にシステムを徐々に組み上げながら段階的に検証していく「Vモデル」と呼ばれる開発プロセスに対応しています。要件定義や詳細設計といった設計工程で作られた仕様が、それぞれのテストフェーズで正しく実現されているかを確認する構造になっています。

テストをこのように複数の段階(テストレベル)に分ける最大の理由は、不具合を早期に発見・修正するためです。ソースコードを作成した直後の単体テストでバグが見つかれば修正コストは数分で済みますが、本番リリース直前やリリース後に不具合が発覚した場合、修正や再検証にかかるコストは何十倍にも跳ね上がってしまいます。

テストレベル 英語表記・主な略称 現場での別称・旧称 主な検証対象 対になる設計工程
単体テスト Unit Test (UT) コンポーネントテスト (CT) / ユニットテスト 関数、クラス、単一モジュール 詳細設計・プログラミング
結合テスト Integration Test (IT) プログラムテスト (PT) / 複合テスト 複数モジュールの連携、API・DB接続 基本設計(詳細設計)
システムテスト System Test (ST) 総合テスト / 体系テスト システム全体の業務フロー、非機能要件 要件定義・基本設計
受け入れテスト User Acceptance Test (UAT) 運用テスト / ユーザーテスト 実業務での操作感、要件充足度の最終確認 事業要件・契約仕様

現場によって略称が異なる理由の背景には、メーカー系SIerの伝統的な呼び方(PT = Program Test)や、Web系企業で主流の英語略記(UT/IT)が混在している事情があります。呼称の揺れに混乱しないよう、それぞれのテストが目指す「検証の範囲と深さ」を把握しておくことが重要です。

2. 単体テスト(UT / Unit Test)の役割と日本語テストケース例

単体テストは英語でUnit Test(ユニットテスト)と呼ばれ、プログラムを構成する最小単位(Unit)が意図通りに動作するかを検証するテスト手法です。

単体テストにおける「Unit(単位)」とは?

Unit Testにおける「Unit」の捉え方には、大きく分けて2つの学派・アプローチが存在します。

  • 孤立型アプローチ(Solitary Unit Testing / デトロイト派): テスト対象のクラスや関数以外の依存関係(他クラス、DB、外部通信など)をすべてテストダブル(モックやスタブ)に置き換え、対象コード1個のみを孤立させて検証する手法。
  • 古典派・協調型アプローチ(Sociable Unit Testing / ロンドン派・シカゴ派): データベースやネットワーク通信などの低速・共有依存のみをモック化し、メモリ上で高速に動く他のドメインクラス同士の連携は実際のオブジェクトのまま一緒にテストする手法。

いずれのアプローチであっても、「数ミリ秒単位で高速に実行できること」「外部環境(DBサーバーやネットワーク状態)に依存せず何度実行しても同じ結果が得られること(決定性)」がUnit Testの核心的な要件となります。

単体テスト仕様書での日本語記述サンプル例

現場の設計書やテスト管理ツール(ExcelやJira、TestRailなど)で実際に記載される、日本語の単体テストケース設計の例です。

テストケースID テスト対象機能・メソッド テスト区分 入力値・条件 期待される結果(日本語判定条件)
UT-CALC-001 会員ランク判定処理
`getMemberRank()`
正常系 年間購入金額: 100,000円 戻り値として「ゴールド会員」ステータスが返却されること。
UT-CALC-002 会員ランク判定処理
`getMemberRank()`
境界値 年間購入金額: 99,999円(ゴールド条件直前) 戻り値として「シルバー会員」ステータスが返却されること。
UT-CALC-003 会員ランク判定処理
`getMemberRank()`
異常系 年間購入金額: -1円(マイナス値) `IllegalArgumentException`(不正引数例外)がスローされること。
UT-AUTH-001 メールアドレス正規化
`normalizeEmail()`
正常系 ` [email protected] `(前後に全角半角空白・大文字混在) トリム処理と小文字化が行われ `[email protected]` に変換されること。

単体テスト(UT)の実装コードサンプル(JavaScript / Python)

上記の日本語テスト仕様に対応する自動テストプログラムのコード例です。

サンプル1: JavaScript (Jest) による境界値とモックのUnit Test

日本語でテストケース内容を `test('日本語での検証内容')` に記述する実務的なJestコード例です。

// priceCalculator.js
function calculateFinalPrice(basePrice, discountService) {
  if (typeof basePrice !== 'number' || basePrice < 0) {
    throw new TypeError("価格は0以上の数値である必要があります");
  }
  const discountRate = discountService.getRate();
  return Math.floor(basePrice * (1 - discountRate));
}

// priceCalculator.test.js (Unit Test)
describe('価格計算モジュール(Unit Test)', () => {
  test('【正常系】1,000円で割引率10%が適用された場合、最終価格が900円となること', () => {
    const mockService = { getRate: jest.fn().mockReturnValue(0.1) };
    expect(calculateFinalPrice(1000, mockService)).toBe(900);
  });

  test('【境界値】基本価格が0円の場合、割引適用後も0円が返却されること', () => {
    const mockService = { getRate: jest.fn().mockReturnValue(0.1) };
    expect(calculateFinalPrice(0, mockService)).toBe(0);
  });

  test('【異常系】基本価格に負の数が指定された場合、TypeErrorが例外スローされること', () => {
    const mockService = { getRate: jest.fn() };
    expect(() => calculateFinalPrice(-1, mockService)).toThrow(TypeError);
  });
});

サンプル2: Python (pytest) によるパラメータ化Unit Test

Pythonの `pytest.mark.parametrize` を活用し、日本語の条件名を含めたテスト実装の例です。

# validator.py
def validate_password(password: str) -> bool:
    if not isinstance(password, str):
        raise ValueError("パスワードは文字列である必要があります")
    length = len(password)
    return 8 <= length <= 16

# test_validator.py (Unit Test)
import pytest
from validator import validate_password

# 境界値のテストケースを一括定義 (7文字, 8文字, 16文字, 17文字)
@pytest.mark.parametrize("password, expected, test_title", [
    ("1234567", False, "境界値: 7文字(最小値未満でNG)"),
    ("12345678", True, "境界値: 8文字(最小値ジャストでOK)"),
    ("1234567890123456", True, "境界値: 16文字(最大値ジャストでOK)"),
    ("12345678901234567", False, "境界値: 17文字(最大値超過でNG)"),
])
def test_validate_password_boundaries(password, expected, test_title):
    # 日本語のテスト条件名をコンソール出力用に維持して検証
    assert validate_password(password) == expected

def test_validate_password_invalid_type():
    """異常系: 数値型が渡された場合にValueErrorが発生すること"""
    with pytest.raises(ValueError):
        validate_password(12345678)

3. 結合テスト(IT/PT)の日本語検証パターンとコードサンプル

結合テスト(IT / PT)では、単体テストをクリアした複数のプログラム、データベース、外部APIを接続した状態でインターフェースのデータの行き来や整合性をチェックします。

結合テスト仕様書での日本語テスト項目サンプル例

結合テストフェーズでよく作成される、モジュール間連携やDB連携の日本語テストケース一覧です。

テストケースID 結合カテゴリ 検証目的・シナリオ テスト手順 期待される結果(日本語判定条件)
IT-USER-001 Web API ↔ DB結合 ユーザー新規登録時にDBレコード作成と初期設定が行われるか 1. POST `/api/v1/users` へ登録リクエスト送信
2. レスポンス受け取り後にDBを検索
・レスポンスコードが201(作成完了)であること
・`users` テーブルおよび `user_profiles` テーブルにレコードが各1件保存されること
IT-PAY-002 外部決済API連携 決済外部サービスがタイムアウトした際の安全なロールバック 1. 注文確定処理を実行
2. 決済API通信で3秒以上の応答遅延(Timeout)を発生させる
・注文ステータスが「決済エラー待ち」に変更されること
・仮確保された在庫数量が元通りキャンセル復元されること
IT-BATCH-001 画面 ↔ 非同期バッチ結合 管理画面からの大量メール配信指示がキュー経由でバッチ処理されるか 1. 管理画面で「お知らせ一括配信」を実行
2. メッセージキュー(Redis等)と配信バッチの動作ログを確認
・配信キューに指定ユーザー数のジョブが投入されること
・バッチログに失敗0件で「一括完了」が記録されること

結合テスト(IT)のコードサンプル(Supertest / Python responses)

サンプル1: Node.js (Supertest) によるWeb API & DBトランザクション結合テスト

実際にテスト用DBをリセットした上でAPIを発行し、レスポンスとDB内部状態の両方を日本語の検証記述でテストするコードです。

// userApi.integration.test.js
const request = require('supertest');
const app = require('../app');
const db = require('../db');

describe('ユーザー登録API 結合テスト (IT)', () => {
  beforeEach(async () => {
    // 結合テスト用にテーブルをリセット
    await db.query('TRUNCATE TABLE users RESTART IDENTITY CASCADE;');
  });

  test('【正常系】正しい入力情報でリクエストすると、ステータス201が返りDBにレコードが正常挿入されること', async () => {
    const newUser = { name: '鈴木一郎', email: '[email protected]' };

    const response = await request(app)
      .post('/api/v1/users')
      .send(newUser);

    // 1. レスポンスヘッダーおよびボディの確認
    expect(response.statusCode).toBe(201);
    expect(response.body.id).toBeDefined();

    // 2. DBを実際にクエリしてデータの永続化を確認
    const dbResult = await db.query('SELECT * FROM users WHERE id = $1', [response.body.id]);
    expect(dbResult.rows.length).toBe(1);
    expect(dbResult.rows[0].email).toBe('[email protected]');
  });
});

サンプル2: Python (responses-mock) による外部決済API連携の結合テスト

外部システムとの通信結果に応じて自社システム側の処理が意図通り切り替わるかをテストするコード例です。

# payment_service.py
import requests

class PaymentService:
    def __init__(self, api_url: str):
        self.api_url = api_url

    def process_payment(self, order_id: str, amount: int) -> dict:
        try:
            res = requests.post(f"{self.api_url}/pay", json={"order_id": order_id, "amount": amount}, timeout=3.0)
            res.raise_for_status()
            return res.json()
        except requests.exceptions.Timeout:
            return {"status": "error", "message": "決済サーバー通信タイムアウト"}

# test_payment_integration.py
import responses
from payment_service import PaymentService

@responses.activate
def test_process_payment_timeout_handling():
    """【結合テスト】外部決済サービスがタイムアウトした際、エラーハンドリング文言が返却されること"""
    service = PaymentService("https://api.payment.example.com")
    
    # 外部APIのタイムアウト発生を模擬(モック通信設定)
    responses.add(
        responses.POST,
        "https://api.payment.example.com/pay",
        body=requests.exceptions.Timeout()
    )
    
    result = service.process_payment("ORD-999", 5000)
    assert result["status"] == "error"
    assert result["message"] == "決済サーバー通信タイムアウト"

4. システムテスト(ST)の自動化コード(Playwright E2E)と観点マトリクス

システムテスト(ST)は、本番環境と同等のテスト環境(Staging等)において、システム全体をエンドユーザーの利用シーンや負荷・障害復旧などの観点から網羅的に検証します。

サンプル1: Playwright を用いたE2E(エンドツーエンド)システムテストコード

実際のWebブラウザを自動操作し、ユーザーの一連の画面導線をテストするPlaywrightスクリプトの例です。

// e2e-login.spec.js (Playwright E2E)
const { test, expect } = require('@playwright/test');

test.describe('ECサイト ログイン・ダッシュボード遷移フロー (ST)', () => {
  test('【画面シナリオ】正しいID・パスワードでログインし、ウェルカムメッセージが表示されること', async ({ page }) => {
    // 1. ログイン画面へ遷移
    await page.goto('https://staging.example.com/login');

    // 2. 日本語フォーム要素への入力操作
    await page.fill('input[name="email"]', '[email protected]');
    await page.fill('input[name="password"]', 'SecurePassword123');
    await page.click('button[type="submit"]');

    // 3. ログイン後のURLおよび画面表示文言の期待値検証
    await expect(page).toHaveURL('https://staging.example.com/dashboard');
    const welcomeBanner = page.locator('.welcome-banner');
    await expect(welcomeBanner).toContainText('ようこそ、[email protected] さん');
  });
});

サンプル2: システムテスト観点一覧(日本語マトリクス仕様例)

システムテスト計画書で作成される、機能要件・非機能要件の具体的テスト項目と合格基準の日本語マトリクスです。

試験分類 検証観点・項目 試験内容・具体的な入力シナリオ 合格判定基準(日本語期待値)
機能テスト 通し業務シナリオ 商品検索 → カート追加 → 決済実行 → 注文完了画面表示 → 注文確認メール受信 一連の処理がエラーなく完了し、購入履歴画面に注文情報が正しく反映されること。
非機能(性能) ピーク負荷試験 模擬ユーザー500名が同時に商品検索APIを一斉実行(10分間継続) ・平均レスポンスタイムが1.5秒以内であること
・HTTP 5xxエラー率が0.01%以下であること
非機能(障害) DBフェイルオーバー オンライン稼働中にプライマリDBサーバーをダウンさせる スタンバイDBへ30秒以内に自動切り替えが行われ、画面に「一時障害」等の案内が正しく表示されること。
非機能(セキュリティ) 脆弱性スキャン 検索フォームおよびURLパラメータにXSS・SQLインジェクションコードを入力 入力値がエスケープ処理され、スクリプト実行や不正なSQL実行が発生しないこと。

5. 受け入れテスト(UAT)の実業務日本語シナリオ仕様書サンプル

受け入れテスト(UAT)では、開発を依頼した顧客や実業務を担当するユーザーが、要件定義通りの使い勝手や業務手順を満たしているかを最終確認します。実際の案件でExcelやプロジェクト管理ツールに記載されるシナリオ仕様書の日本語例です。

シナリオID 検証テーマ・業務目的 前提条件 エンドユーザーの操作手順 期待される結果(合格判断ルール) 判定・確認者
UAT-FIN-001 月末締め売上データのCSV出力と経理会計ソフト取り込み検証 当月分のテスト注文データが50件以上登録済みであること 1. 管理画面の「売上集計」を開く
2. 当月期間を選択し「経理用CSV出力」ボタンをクリック
3. ダウンロードしたファイルを指定フォーマットで開く
・出力ファイル名が `sales_202607.csv` であること
・合計売上額および消費税額が管理画面の表示額と完全に一致すること
・会計ソフトのインポート機能でエラーなく取り込めること
経理部 担当者
UAT-CS-002 CS窓口での顧客注文キャンセル受付と返金処理フローの動作確認 「発送準備中」ステータスのテスト注文が存在すること 1. CS管理画面で該当の注文番号を検索
2. 「注文キャンセル」ボタンを押し、理由「顧客都合」を選択して確定
3. 顧客マイページの購入履歴を確認
・注文ステータスが「キャンセル完了」に変更されること
・クレジットカードの与信枠取消通知メールが顧客宛てに送信されること
・倉庫側出荷システムにキャンセル連携が即座に反映されること
CSチーム リーダー
UAT-INV-003 実店舗とECサイトでの同一商品同時購入による在庫引き当て検証 残り在庫数が「1個」の商品を用意すること 1. 店舗レジ(POS)とECサイトで同時に該当商品を決済
2. 先に決済完了した側と遅れた側の画面表示を確認
・タッチの差で遅れた側に「在庫切れ」エラーが正しく案内されること
・実在庫数がマイナス(二重引き当て)にならないこと
店舗・EC運用担当

6. 現場でのテスト設計・実施で直面する課題と有益なプラクティス

理論上は「UT → IT → ST → UAT」と順を追って進むように見えるテスト工程ですが、実際の現場ではいくつかの現実的な課題に直面します。

① 単体テスト(Unit Test)で「モックを作りすぎる」罠

単体テストの独立性を意識するあまり、データベース接続も外部クラスもすべてモック化してしまうケースがあります。その結果、UTはすべてグリーン(合格)なのに、モックの仕様自体が実物とズレていてITでエラーが頻発する、という事態が起こります。モック化は外部通信や処理速度の遅い部分に限定し、ドメインロジックは実オブジェクトに近い形でテストする設計が推奨されます。

② テスト自動化の切り分け(テストピラミッド方針)

すべてのテストレベルを手動または自動で行うのはコスト的に現実的ではありません。一般的には「テストピラミッド」の考え方が有用とされています。

  • 単体テスト(UT / Unit Test): 大量に作成し、CI/CDツール(GitHub ActionsやGitLab CIなど)でPull Request作成ごとに100%自動実行する。
  • 結合テスト(IT): 主要なAPIエンドポイントやDB連携を中心に自動化し、定期ビルドや夜間テストで回す。
  • UI / システムテスト(ST): PlaywrightやCypressなどのE2Eテストツールを用いてクリティカルなメイン導線のみ自動化し、細かな画面表示の崩れや使い勝手は手動検証を組み合わせる。

それぞれのテストレベルが持つ目的や対象範囲をチーム全体で共通認識として持っておくことが、過不足のないテスト計画を立てる第一歩になります。