Jestでオブジェクトや配列を比較する際、expect(...).toEqual(...)を使って比較することが一般的です。しかし、オブジェクト内にタイムスタンプなどの動的に変化するデータが含まれている場合、そのままtoEqualを使うとテストは失敗します。
このような場合、expect.anything()やexpect.any()を使うことで、動的なデータの曖昧比較が可能になります。
この記事では、expect.anythingとexpect.anyの使い方についてサンプルコードを用いてわかりやすく解説します。
expect.anythingとは
expect.anything()は、Jestで使われるマッチャーで、nullやundefined以外のすべての値に一致させたい場合に使用します。特定の値にはこだわらず、値が「存在している」ことさえ確認できれば良い場合に便利です。
例えば、以下のようにタイムスタンプを含むオブジェクトをテストする場合を考えてみます。
test('オブジェクトの値が一致することを確認する', () => {
const obj = {
id: 1,
name: 'Ken',
createdAt: Date.now(), // タイムスタンプ
};
expect(obj).toEqual({
id: 1,
name: 'Ken',
createdAt: Date.now(), // これではタイムスタンプが一致せず失敗する
});
});上記のサンプルコードでは、createdAtがテスト実行時に動的に変わるため、toEqualでの比較が失敗します。しかし、expect.anything()を使用することで、createdAtがnullやundefinedでなければテストが通るようにできます。
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()はテスト対象が「nullやundefined以外の値」であれば、テストが通ります。もう少し厳密にテストをしたい場合には、expect.any()を用います。
expect.any()は、特定のデータ型に一致するかどうかを確認するためのJestのマッチャーです。例えば、NumberやStringなどの特定のコンストラクタに基づく型であることを検証したい場合に使用します。これにより、特定の値ではなく「指定した型に一致するか」を確認することができます。
例えば、createdAtがNumber型(タイムスタンプ)であることを確認する場合、次のように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)を使うことで、createdAtがNumber型であることを保証しつつ、テストを行うことができます。
expect.anythingとexpect.anyの違い
expect.anything()とexpect.any()には次のような違いがあります。
expect.anything()nullやundefined以外のすべての値にマッチします。値そのものにはこだわらず、値が「存在している」ことを確認したい場合に使用します。
expect.any(Constructor)- 特定のデータ型(コンストラクタ)に一致させたい場合に使用します。例えば、
NumberやStringなどの型に基づく値を厳密に検証したい場合に便利です。
- 特定のデータ型(コンストラクタ)に一致させたい場合に使用します。例えば、
以下の例では、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()を適切に活用することで、動的データを含む複雑なオブジェクトや配列のテストを、シンプルかつ効果的に行うことができます。
お読み頂きありがとうございました。