モック

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

テスト設計

モックとは

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

テストダブルの種類

テストダブルの種類を以下にまとめる。

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

Vitest でのモック

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 (インメモリ実装)

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())

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

この記事は役に立ちましたか?

関連用語

関連する記事