【Jest】expect.anythingとexpect.anyとは?使い方を解説!

Jestでオブジェクトや配列を比較する際、expect(...).toEqual(...)を使って比較することが一般的です。しかし、オブジェクト内にタイムスタンプなどの動的に変化するデータが含まれている場合、そのままtoEqualを使うとテストは失敗します。

このような場合、expect.anything()expect.any()を使うことで、動的なデータの曖昧比較が可能になります。

この記事では、expect.anythingexpect.anyの使い方についてサンプルコードを用いてわかりやすく解説します。

expect.anythingとは

expect.anything()は、Jestで使われるマッチャーで、nullundefined以外のすべての値に一致させたい場合に使用します。特定の値にはこだわらず、値が「存在している」ことさえ確認できれば良い場合に便利です。

例えば、以下のようにタイムスタンプを含むオブジェクトをテストする場合を考えてみます。

test('オブジェクトの値が一致することを確認する', () => {
  const obj = {
    id: 1,
    name: 'Ken',
    createdAt: Date.now(), // タイムスタンプ
  };
  expect(obj).toEqual({
    id: 1,
    name: 'Ken',
    createdAt: Date.now(), // これではタイムスタンプが一致せず失敗する
  });
});

上記のサンプルコードでは、createdAtがテスト実行時に動的に変わるため、toEqualでの比較が失敗します。しかし、expect.anything()を使用することで、createdAtnullundefinedでなければテストが通るようにできます。

test('オブジェクトの値が一致することを確認する', () => {
  const obj = {
    id: 1,
    name: 'Ken',
    createdAt: Date.now(), // タイムスタンプ
  };
  expect(obj).toEqual({
    id: 1,
    name: 'Ken',
    createdAt: expect.anything(), // nullやundefined以外ならOK
  });
});

これにより、タイムスタンプが動的に変わっても、createdAtが値を持っている限りテストが通過します。

また、オブジェクトだけでなく、配列の要素やtoHaveBeenCalledWithにも使用できます。サンプルコードを以下に示します。

test('配列の要素が一致することを確認する', () => {
  const arr = [1, 'Ken', Date.now()];
  expect(arr).toEqual([1, 'Ken', expect.anything()]);
});

test('関数の引数が一致することを確認する', () => {
  const mockFunction = jest.fn();
  mockFunction(1, 'Ken', Date.now());
  expect(mockFunction).toHaveBeenCalledWith(1, 'Ken', expect.anything());
});

補足

なお、以下のようにtoBeを使ってプロパティごとに個別で比較することも可能です。ただし、プロパティ数が増えると手間がかかるため、expect.anything()expect.any()を使う方が効率的です。

test('オブジェクトの値が一致することを確認する', () => {
  const obj = {
    id: 1,
    name: 'Ken',
    createdAt: Date.now(), // タイムスタンプ
  };

  // プロパティ個別で比較している。プロパティが増えると面倒!!
  expect(obj.id).toBe(1);
  expect(obj.name).toBe('Ken');
  expect(typeof obj.createdAt).toBe('number'); // タイムスタンプが数値であることを確認
});

expect.anyとは

expect.anything()はテスト対象が「nullundefined以外の値」であれば、テストが通ります。もう少し厳密にテストをしたい場合には、expect.any()を用います。

expect.any()は、特定のデータ型に一致するかどうかを確認するためのJestのマッチャーです。例えば、NumberStringなどの特定のコンストラクタに基づく型であることを検証したい場合に使用します。これにより、特定の値ではなく「指定した型に一致するか」を確認することができます。

例えば、createdAtNumber型(タイムスタンプ)であることを確認する場合、次のようにexpect.any(Number)を使用します。

test('オブジェクトの値が一致することを確認する', () => {
  const obj = {
    id: 1,
    name: 'Ken',
    createdAt: Date.now(),
  };

  expect(obj).toEqual({
    id: 1,
    name: 'Ken',
    createdAt: expect.any(Number), // Number型であればOK
  });
});

この例では、createdAtが数値であることを検証しています。expect.any(Number)を使うことで、createdAtNumber型であることを保証しつつ、テストを行うことができます。

expect.anythingとexpect.anyの違い

expect.anything()expect.any()には次のような違いがあります。

  • expect.anything()
    • nullundefined以外のすべての値にマッチします。値そのものにはこだわらず、値が「存在している」ことを確認したい場合に使用します。
  • expect.any(Constructor)
    • 特定のデータ型(コンストラクタ)に一致させたい場合に使用します。例えば、NumberStringなどの型に基づく値を厳密に検証したい場合に便利です。

以下の例では、expect.anything()expect.any(Number)を使って異なる部分を検証しています。

test('オブジェクトの値が一致することを確認する', () => {
  const obj = {
    id: 1,
    name: 'Ken',
    createdAt: Date.now(),
  };

  // expect.anythingを使ってcreatedAtが存在することだけ確認
  expect(obj).toEqual({
    id: 1,
    name: 'Ken',
    createdAt: expect.anything(), // nullやundefined以外ならOK
  });

  // expect.anyを使ってcreatedAtが数値であることを確認
  expect(obj).toEqual({
    id: 1,
    name: 'Ken',
    createdAt: expect.any(Number), // Number型であればOK
  });
});

本記事のまとめ

この記事ではexpect.anything()expect.any()の使い方について説明しました。

expect.anything()expect.any()を適切に活用することで、動的データを含む複雑なオブジェクトや配列のテストを、シンプルかつ効果的に行うことができます。

お読み頂きありがとうございました。