モック

テスト時に外部依存を模倣するオブジェクトで、テストの独立性と速度を確保する

テスト設計

モックとは

モック (Mock) は、テスト時に外部依存 (DB、API、ファイルシステム) を模倣するオブジェクトで、テストの独立性と速度を確保する。実際の DB に接続せずにテストを実行でき、ネットワーク障害などの異常系もシミュレートできる。

テストダブルの種類

種類 説明
Mock 呼び出しを記録し、期待通りに呼ばれたか検証 vi.fn()
Stub 固定値を返す vi.fn().mockReturnValue(42)
Spy 実際の関数を呼びつつ、呼び出しを記録 vi.spyOn(obj, 'method')
Fake 簡易的な実装 (InMemory DB) InMemoryUserRepository

Vitest でのモック

import { vi, describe, it, expect } from 'vitest';

// 関数のモック
const getUser = vi.fn().mockResolvedValue({ id: '1', name: 'Alice' });

// モジュールのモック
vi.mock('./db', () => ({
  getUser: vi.fn().mockResolvedValue({ id: '1', name: 'Alice' }),
}));

describe('OrderService', () => {
  it('ユーザーが存在する場合に注文を作成する', async () => {
    const result = await createOrder('1', [{ productId: 'P1', qty: 2 }]);
    expect(result.status).toBe('created');
    expect(getUser).toHaveBeenCalledWith('1');
  });
});

モックしすぎの問題

// ❌ モックしすぎ: テストが実装の詳細に依存
it('should call db.put with correct params', () => {
  createUser({ name: 'Alice' });
  expect(db.put).toHaveBeenCalledWith({
    TableName: 'users',
    Item: { id: expect.any(String), name: 'Alice' },
  });
});
// → db.put の引数が変わるとテストが壊れる (実装の詳細)

// ✅ 振る舞いをテスト
it('should create a user and return it', async () => {
  const user = await createUser({ name: 'Alice' });
  expect(user.name).toBe('Alice');
  expect(user.id).toBeDefined();
});

Fake (インメモリ実装)

class InMemoryUserRepository implements UserRepository {
  private store = new Map<string, User>();
  async findById(id: string) { return this.store.get(id) ?? null; }
  async save(user: User) { this.store.set(user.id, user); }
}

// テストで使用
const repo = new InMemoryUserRepository();
const service = new UserService(repo);

Fake はモックより実装に近く、テストの信頼性が高い。

モックの判断基準

ケース 推奨
外部 API (HTTP) ✅ モック
DB (DynamoDB) Fake (InMemory) or モック
純粋関数 ❌ モック不要
時刻 (Date.now()) ✅ モック (vi.useFakeTimers())

モックを扱う関連書籍も多い。

関連用語