単体テスト vs 結合テスト vs システムテスト:違いとは?

Ashley Goolam

Ashley Goolam

23 12月 2025

単体テスト vs 結合テスト vs システムテスト:違いとは?

ユニットテスト、結合テスト、システムテストの比較は、経験豊富な開発者でさえ混乱させることがあります。これら3つのテストレベルはソフトウェア品質の基盤を形成しますが、チームはしばしばそれらを誤用し、浅すぎる、あるいは維持するのが非常に高価なテストスイートを作成してしまいます。それぞれのテストがあなたのテスト戦略のどこに当てはまるかを理解することは学問的なことではなく、出荷の速さやリリースへの自信に直接影響します。

このガイドでは、各テストレベルの範囲、目的、タイミングを明確にし、それらがテストピラミッド内でどのように連携するかを示し、すぐに適用できる実用的な例も提供します。マイクロサービス、モノリス、APIを開発しているかどうかにかかわらず、ユニットテスト、結合テスト、システムテストの違いを理解することは不可欠です。

ボタン

ユニットテストとは?

ユニットテストは、アプリケーションの最小のテスト可能な部分(個々の関数、メソッド、またはクラス)を完全に分離して検証します。目標は、各ユニットがその仕様に従って正しく動作することを示すことです。

範囲と例

ユニットテストは、依存関係なしにロジックの1つの部分を検査します。簡単な例を次に示します。

// Function under test
function calculateDiscount(price, discountPercent) {
  if (discountPercent < 0 || discountPercent > 100) {
    throw new Error('Invalid discount percentage');
  }
  return price * (discountPercent / 100);
}

// Unit test
describe('calculateDiscount', () => {
  it('calculates 20% discount correctly', () => {
    expect(calculateDiscount(100, 20)).toBe(20);
  });
  
  it('throws error for negative discount', () => {
    expect(() => calculateDiscount(100, -5)).toThrow();
  });
});

テストが入力を行い、直接出力を検証することに注目してください。データベース、API、UIは関与していません。

長所と短所

長所:

短所:

結合テストとは?

結合テストは、複数のコンポーネントが正しく連携して動作することを確認します。APIエンドポイント、データベース接続、メッセージキュー、サービス間の相互作用など、ユニット間のインターフェースに焦点を当てます。

範囲と例

以下は、データベースに触れるユーザー登録エンドポイントの結合テストです。

// Integration test for POST /api/users
describe('User Registration API', () => {
  it('creates user and stores in database', async () => {
    const userData = {
      name: 'Test User',
      email: 'test@example.com',
      password: 'ValidPass123'
    };
    
    // Act: Call the actual API
    const response = await axios.post('http://localhost:3000/api/users', userData);
    
    // Assert: Check response AND database
    expect(response.status).toBe(201);
    expect(response.data).toHaveProperty('userId');
    
    // Verify database state
    const userInDb = await db.users.findByEmail('test@example.com');
    expect(userInDb).toBeTruthy();
    expect(userInDb.name).toBe('Test User');
  });
});

このテストは、API、ビジネスロジック、およびデータベースの結合が連携して動作することを示しています。

長所と短所

長所:

短所:

システムテストとは?

システムテストは、完成した統合システムがビジネス要件に合致しているかを検証します。アプリケーションをブラックボックスとして扱い、ユーザーの視点からエンドツーエンドのワークフローをテストします。

範囲と例

Eコマースの購入ワークフローに対するシステムテストを次に示します。

// System test: Complete purchase flow
describe('E-commerce Purchase System', () => {
  it('allows user to browse, add to cart, and checkout', async () => {
    // Step 1: User registration
    const user = await api.register('shopper@example.com', 'password');
    
    // Step 2: Browse products
    const products = await api.searchProducts('laptop');
    expect(products.length).toBeGreaterThan(0);
    
    // Step 3: Add to cart
    await api.addToCart(user.token, products[0].id, 1);
    
    // Step 4: Checkout
    const order = await api.checkout(user.token, {
      shippingAddress: '123 Main St',
      paymentMethod: 'visa'
    });
    
    // Oracle: Verify complete order
    expect(order.status).toBe('confirmed');
    expect(order.total).toBeGreaterThan(0);
    
    // Verify side effects
    const inventory = await api.getInventory(products[0].id);
    expect(inventory.stock).toBe(initialStock - 1);
  });
});

これは複数のAPI、データベース、および外部サービス(決済ゲートウェイ)にまたがっています。

長所と短所

長所:

短所:

ソフトウェアテストピラミッド:3つの関係性

テストピラミッドは、ユニットテスト、結合テスト、システムテストがどのように分散されるべきかを視覚化します。

        System Tests (10%)
            ▲
    Integration Tests (30%)
            ▲
    Unit Tests (60%)

下層(ユニットテスト): 最も数が多く、実行が速く、常に実行される
中層(結合テスト): 中程度の数で、重要な結合を検証
上層(システムテスト): 最も数が少なく、主要なビジネスワークフローをテスト

この形状は、高速なフィードバックを保証しつつ、信頼性を維持します。ピラミッドを逆転させると(多くのシステムテスト、少数のユニットテスト)、テストスイートは遅く、壊れやすく、高価になります。

software testing pyramid

各テストの実施時期:ライフサイクル統合

開発フェーズ 主要なテストタイプ 頻度 実行時間
コード記述時 ユニットテスト 保存するたび 1秒未満
プルリクエスト時 ユニット + 結合テスト コミット前 1〜5分
マージ前 結合テスト + 一部のシステムテスト PR承認時 5〜15分
ナイトリービルド時 フルスイート(全タイプ) 毎日 30〜60分
リリース前 システムテスト + スモークテスト デプロイ前 15〜30分
本番環境 スモークテスト + モニタリング 継続的 リアルタイム

ユニットテスト、結合テスト、システムテストのタイミングを適切に設定することで、品質ゲートを意味のあるものに保ちながら、ボトルネックを防ぐことができます。

比較表:適切なテストの選択

要素 ユニットテスト 結合テスト システムテスト
速度 ⚡⚡⚡ 非常に速い ⚡⚡ 中程度 ⚡ 遅い
分離度 高い 中程度 低い
デバッグしやすさ 容易 中程度 困難
信頼性 低い 中程度 高い
メンテナンス性 低い 中程度 高い
記述時期 コーディング前/中 ユニット動作後 結合後
誰が記述するか 開発者 開発者 + QA QA + 開発者

実践例:APIエンドポイントのテスト

POST /api/usersエンドポイントにおけるユニットテスト、結合テスト、システムテストの動作を見てみましょう。

ユニットテスト(バリデーションロジックのテスト)

// Test only the validation function
describe('validateUser', () => {
  it('rejects invalid email', () => {
    const result = validateUser({ email: 'invalid' });
    expect(result.isValid).toBe(false);
    expect(result.errors).toContain('Invalid email format');
  });
});

結合テスト(API + データベースのテスト)

// Test API layer with real database
describe('POST /api/users integration', () => {
  it('creates user in database', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'Test', email: 'test@example.com' });
    
    expect(response.status).toBe(201);
    
    // Oracle: Verify database
    const user = await db.users.findByEmail('test@example.com');
    expect(user.name).toBe('Test');
  });
});

システムテスト(完全なワークフローのテスト)

// Test registration → login → profile update
describe('User management system', () => {
  it('allows complete user lifecycle', async () => {
    // Register
    const reg = await api.post('/api/users', userData);
    expect(reg.status).toBe(201);
    
    // Login
    const login = await api.post('/api/auth/login', credentials);
    expect(login.data.token).toBeTruthy();
    
    // Update profile
    const update = await api.put('/api/users/me', updates, {
      headers: { Authorization: `Bearer ${login.data.token}` }
    });
    expect(update.status).toBe(200);
    
    // Verify final state
    const profile = await api.get('/api/users/me', {
      headers: { Authorization: `Bearer ${login.data.token}` }
    });
    expect(profile.data.name).toBe(updates.name);
  });
});

Apidogが開発チームのAPIテストをどのように支援するか

ユニットテスト、結合テスト、システムテストを理解することは重要ですが、APIにそれらを実装するのは面倒な場合があります。Apidogは、特に結合テストとシステムテストにおいて、重労働を自動化します。

テストオラクルの自動生成

結合テストの場合、ApidogはOpenAPI仕様から直接テストオラクルを生成します。

# From your API spec, Apidog generates:
Test: POST /api/users
Oracle 1: Status must be 201
Oracle 2: Response must match User schema
Oracle 3: Location header must exist
Oracle 4: Response time < 500ms
Oracle 5: Database query returns created user

これにより、手動でのオラクルの定義が不要になり、テストがAPI契約と同期した状態に保たれます。

システムテストのためのビジュアルテストビルダー

Apidogでは、複雑なワークフローのシステムテストが視覚的に行えます。

Test: Complete User Onboarding
1. POST /api/users (create)
2. POST /api/auth/verify (email verification)
3. POST /api/auth/login (authenticate)
4. GET /api/dashboard (load data)
5. POST /api/preferences (set preferences)

Assertions at each step + final state validation

これは、API呼び出しをドラッグ&ドロップで構築でき、Apidogが認証、データ連鎖、アサーションを自動的に処理します。

ボタン
testing in apidog

継続的テストのためのCI/CD統合

Apidogは、CI/CDでユニットテスト、結合テスト、システムテストの階層を実行します。

# GitHub Actions pipeline
- name: Run Unit Tests
  run: npm test:unit

- name: Run Apidog Integration Tests
  run: apidog run --tags "@integration"

- name: Run Apidog System Tests
  run: apidog run --tags "@system"

これにより、各テストタイプが適切な段階で実行され、結果がSlackやメールに直接投稿されます。

ci/cd in apidog

テストカバレッジの可視化

Apidogは、どのAPIがユニットテスト、結合テスト、システムテストのカバレッジを持っているかを表示します。

エンドポイント ユニット 結合 システム カバレッジ
POST /users 100%
GET /users/:id 67%
DELETE /users 67%

この可視性により、チームは戦略的にテストのギャップを埋めることができます。

よくある質問

Q1: APIエンドポイントにユニットテストを書くべきですか?

回答:APIエンドポイントはロジックをオーケストレーションするため、結合テストを持つべきです。エンドポイント内のビジネスロジックは、別途ユニットテストでテストすべきです。

Q2: どれくらいの結合テストがあれば十分ですか?

回答:すべての重要なパスとエラーシナリオをカバーしてください。良いルールとして、結合のバグが本番環境に到達する可能性がある場合、それに対してテストを書くべきです。

Q3: システムテストはメンテナンスコストに見合う価値がありますか?

回答:はい、ただし主要なビジネスワークフローに限定されます。ビジネス価値の80%を生み出す機能の10〜20%にシステムテストを制限してください。

Q4: Apidogはユニットテストを生成できますか?

回答:いいえ。ユニットテストは内部コード構造の知識を必要とします。Apidogは、外部からAPIの動作を観察できる結合テストとシステムテストに優れています。

Q5: 新しいプロジェクトではどのテストタイプを優先すべきですか?

回答:ユニットテスト(基盤)から始め、コンポーネントが接続されたら結合テストを追加し、次に重要なユーザー体験のためにシステムテストを追加します。このピラミッドアプローチは技術的負債を防ぎます。

結論

ユニットテスト、結合テスト、システムテストの決定は、どちらか一方を選ぶことではなく、それぞれを適切なタイミングと割合で適用することです。ユニットテストは開発の速度と正確性をもたらします。結合テストは、ユニットテストが見逃す接続の問題を捕捉します。システムテストは、製品全体がユーザーのために機能するという信頼を提供します。

この階層を習得すれば、あなたのテストスイートはメンテナンスの負担ではなく、戦略的な資産となります。まず、現在のテスト分布を監査することから始めましょう。多くの遅くて壊れやすいシステムテストで逆ピラミッドになっていませんか?焦点を下にシフトしてください。重要な結合テストのカバレッジが不足していませんか?それらのギャップを埋めてください。

Apidogのような最新ツールは、テストの作成と実行を自動化することで、結合層とシステム層をはるかに管理しやすくします。これにより、開発速度を落とすことなく、テストピラミッドの形状を維持できます。品質は、リリースを遅らせる別のフェーズではなく、プロセスの自然な結果となります。

覚えておいてください。目標はすべてをテストすることではなく、適切なレベルで適切なものをテストすることです。ユニットテスト、結合テスト、システムテストがあなたの戦略で明確であれば、出荷は予測可能になり、信頼性が高まり、チームは問題解決に費やす時間を減らし、価値創造に多くの時間を費やすことができます。

ボタン

ApidogでAPIデザイン中心のアプローチを取る

APIの開発と利用をよりシンプルなことにする方法を発見できる