👏

モックとスタブの違いを聞かれて即答できなかったので調べました

2024/02/22に公開

モックとスタブはどちらもテストダブルの一種

  • テストダブルはテストの利便性を上げるツールであり、モックとスタブはその一種
  • ただし、それぞれテストの異なる側面に焦点を当てるために用いられる

モックの使い所

期待される相互作用の検証に用いる

  • 特定のメソッドが呼び出されたか、期待される引数で呼び出されたか、何回呼び出されたかなど、相互作用の詳細を検証するために使用される
    • メールを送信する sendEmail という関数があったとする
    • 正しく呼び出されたかどうかのみをテストするので、引数が意図したものかどうかをチェックして実際の処理(メール送信)は行わない

使用イメージとしては以下

import { sendEmail } from "./emailService";

describe("sendEmail function", () => {
  it("should call sendEmail with correct parameters", () => {
    const mockSendEmail = jest.fn();
    sendEmail = mockSendEmail;

    sendEmail("test@example.com", "Test Subject", "Hello, this is a test");

    expect(mockSendEmail).toHaveBeenCalledWith(
      "test@example.com",
      "Test Subject",
      "Hello, this is a test",
    );
  });
});

スタブの使い所

特定のレスポンスの提供を目的に使用される

  • 関数が呼び出されたかどうかをテストするためではなく、スタブが特定の入力に対して予め定義されたレスポンスを提供する
  • 外部システムや時間のかかる処理を模倣するために使用されることが多い
    • 例えば、APIリクエストを行なってそのレスポンスをベースにオブジェクトを生成するような処理がある場合
      • 実際にAPIリクエストを行わずレスポンスを模したダミーデータを代用する

使用イメージとしては以下

global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () =>
      Promise.resolve({ id: 1, name: "Test User", email: "test@example.com" }),
  }),
);

describe("fetchUserData function", () => {
  it("should fetch user data correctly", async () => {
    const userData = await fetchUserData(1);

    expect(fetch).toHaveBeenCalledWith("https://example.com/api/users/1");
    expect(userData).toEqual({
      id: 1,
      name: "Test User",
      email: "test@example.com",
    });
  });

  afterEach(() => {
    jest.clearAllMocks();
  });
});

最後に

Next.js で決済機能を実装する本を書いたのでよかったら読んでください。

https://zenn.dev/k0kishima/books/f07cffba6e0fab

Discussion