Vitestで非同期関数をモックする方法とハマりやすいポイント

Vitestは、モダンなJavaScriptアプリケーションのテストを簡単に行うための強力なツールです。特に非同期関数のテストにおいては、モックを使用することで外部依存を排除し、テストの安定性を向上させることができます。

本記事では、Vitestで非同期関数をモックする方法と、ハマりやすいポイントについて詳しく解説します。

非同期関数のモックが必要な理由

非同期関数をテストする際、実際のAPI呼び出しやデータベースアクセスを行うと、テストが遅くなったり、外部サービスの状態に依存してしまいます。これにより、テストが不安定になり、結果が一貫しないことがあります。そこで、モックを使用して非同期関数の動作をシミュレートすることが重要です。

  • テストの速度向上
    • 実際のリクエストを行わないため、テストが迅速に実行されます。
  • 外部依存の排除
    • 外部サービスの状態に依存せず、常に同じ結果を得ることができます。
  • エラー処理のテスト
    • モックを使用することで、特定のエラーを簡単にシミュレートできます。

Vitestで非同期関数をモックする基本的な方法

Vitestでは、非同期関数をモックするためにvi.fn()vi.mock()を使用します。以下に、基本的な使い方を示します。

1. vi.fn()を使用したモック

vi.fn()を使用して、非同期関数をモックすることができます。以下は、非同期関数のモックの例です。

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

// 非同期関数の定義
const fetchData = async () => {
  const response = await fetch('https://api.example.com/data');
  return response.json();
};

// テスト
it('fetchData should return mock data', async () => {
  const mockData = { id: 1, name: 'Test' };
  
  // fetchをモック
  global.fetch = vi.fn().mockResolvedValue({
    json: vi.fn().mockResolvedValue(mockData),
  });

  const data = await fetchData();
  expect(data).toEqual(mockData);
});

この例では、fetchData関数がAPIからデータを取得する際に、fetchをモックして、常に指定したデータを返すようにしています。

2. vi.mock()を使用したモック

モジュール全体をモックする場合は、vi.mock()を使用します。以下は、モジュールをモックする例です。

// api.js
export const fetchData = async () => {
  const response = await fetch('https://api.example.com/data');
  return response.json();
};

// api.test.js
import { it, expect, vi } from 'vitest';
import * as api from './api';

vi.mock('./api', () => ({
  fetchData: vi.fn(),
}));

it('fetchData should return mock data', async () => {
  const mockData = { id: 1, name: 'Test' };
  api.fetchData.mockResolvedValue(mockData);

  const data = await api.fetchData();
  expect(data).toEqual(mockData);
});

この例では、api.jsモジュールのfetchData関数をモックし、テスト内で指定したデータを返すようにしています。

ハマりやすいポイント

非同期関数をモックする際には、いくつかのハマりやすいポイントがあります。これらを理解しておくことで、テストの信頼性を高めることができます。

1. モックのリセット

テストが複数ある場合、モックの状態が前のテストから影響を受けることがあります。これを防ぐために、各テストの前にモックをリセットすることが重要です。

beforeEach(() => {
  vi.clearAllMocks(); // モックのリセット
});

2. 非同期処理の待機

非同期関数をテストする際、結果が返る前にアサーションを行うと、テストが失敗することがあります。これを避けるために、awaitを使用して非同期処理が完了するのを待つ必要があります。

it('should wait for async data', async () => {
  const mockData = { id: 1, name: 'Test' };
  global.fetch = vi.fn().mockResolvedValue({
    json: vi.fn().mockResolvedValue(mockData),
  });

  const data = await fetchData(); // awaitを使用
  expect(data).toEqual(mockData);
});

3. モックのスコープ

モックは、テストファイル内でのみ有効です。他のテストファイルで同じモックを使用する場合は、再度モックを定義する必要があります。これにより、テストの可読性が向上しますが、モックの重複を避けるために注意が必要です。

非同期関数のエラー処理をテストする

非同期関数のエラー処理をテストする際も、モックを活用できます。以下は、エラーをシミュレートする例です。

it('fetchData should throw an error', async () => {
  global.fetch = vi.fn().mockRejectedValue(new Error('Network Error'));

  await expect(fetchData()).rejects.toThrow('Network Error');
});

この例では、fetchがエラーを返すようにモックし、fetchData関数が正しくエラーをスローするかをテストしています。

まとめ

Vitestを使用して非同期関数をモックする方法と、ハマりやすいポイントについて解説しました。モックを活用することで、テストの速度や安定性を向上させることができます。

特に、非同期処理のテストでは、モックの使い方を理解しておくことが重要です。これにより、より信頼性の高いテストを実現できるでしょう。

参考

タイトルとURLをコピーしました