⚙️

expected "spy" to be called 1 times, but got 2 times エラーの対処法

に公開

環境

  • テストフレームワーク: Vitest
  • モックライブラリ: vi.mock を使用
  • テストランナー: Vitest が提供する test 関数
  • モジュールのモック: vi.mock を使用して対象モジュールをモック化
  • モック関数の管理: vi.clearAllMocks() を使用してモック関数の呼び出し履歴をリセット

概要

テストを実行している際に、以下のようなエラーに遭遇することがあります。

expected "spy" to be called 1 times, but got 2 times

このエラーは、モック関数(spy)が期待された回数(例: 1回)よりも多く呼び出された場合に発生します。本記事では、このエラーの原因と解決方法を解説します。

エラーの原因

このエラーが発生する主な原因は以下の通りです。

1. モック関数の呼び出し履歴がリセットされていない

テスト間でモック関数の呼び出し履歴が共有されている場合、前のテストの呼び出し履歴が次のテストに影響を与えることがあります。

2. テストコード内で関数が複数回呼び出されている

テスト内で意図せず同じモック関数を複数回呼び出している可能性があります。

3. テスト対象のコードが関数を複数回呼び出している

テスト対象の関数やモジュール内で、モック関数が意図せず複数回呼び出されている可能性があります。

解決方法

1. モック関数の呼び出し履歴をリセットする

テスト間でモック関数の呼び出し履歴が共有されないように、beforeEach フックを使用して各テストの前にモック関数の履歴をクリアします。

具体的には以下のように vi.clearAllMocks() を追加します。

import { beforeEach, vi } from 'vitest';

// 各テストの前にモック関数の呼び出し履歴をクリア
beforeEach(() => {
  vi.clearAllMocks();
});

これにより、各テストが独立して実行され、他のテストの影響を受けなくなります。

2. テストコードを確認する

テスト内でモック関数が意図せず複数回呼び出されていないか確認します。例えば、以下のようなコードが原因になることがあります。

const result1 = await fetchNews(); // 1回目の呼び出し
const result2 = await fetchNews(); // 2回目の呼び出し

この場合、モック関数が2回呼び出されるため、toHaveBeenCalledTimes(1) のアサーションが失敗します。必要に応じて、呼び出し回数を調整してください。

3. テスト対象のコードを確認する

テスト対象の関数やモジュール内で、モック関数が意図せず複数回呼び出されていないか確認します。例えば、以下のようなコードが原因になることがあります。

async function fetchData() {
  await fetchNews(); // 1回目の呼び出し
  await fetchNews(); // 2回目の呼び出し
}

この場合、テスト対象のコードを修正するか、テストの期待値を変更して呼び出し回数を正しく設定します。

Discussion