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を使用して非同期関数をモックする方法と、ハマりやすいポイントについて解説しました。モックを活用することで、テストの速度や安定性を向上させることができます。
特に、非同期処理のテストでは、モックの使い方を理解しておくことが重要です。これにより、より信頼性の高いテストを実現できるでしょう。