Vitest で Table Driven Test (テーブル駆動テスト) のアプローチ
Table-Driven Testing (テーブル駆動テスト) は、ソフトウェアのテスト手法の一つで、テストケースをテーブル単位でまとめ、それをもとにテストを実行する方法です。この手法は、同じ処理に対して異なる入力値を与え、その結果が期待通りかどうかを確認する際に特に有効です。
Table Driven Test と検索すると Go 言語の事例が多くでます。これは、Go 言語の公式 Wiki でも紹介されています。
Table Driven Test を実践する
まずは、テスト対象のシンプルなメソッドを作成しましょう。非常にシンプルな例ですが、add 関数に a と b を入力すると、合計値を返します。一般的にテストを書くとしたら以下のようになります。
import { describe, expect, test } from "vitest";
const add = (a: number, b: number) => a + b;
describe("Add", () => {
test("adds 1 + 2 to return 3", () => {
expect(add(1, 2)).toBe(3);
});
test("adds 2 + 3 to return 5", () => {
expect(add(2, 3)).toBe(5);
});
test("adds 3 + 4 to return 7", () => {
expect(add(3, 4)).toBe(7);
});
})
これを Table Driven Test のアプローチで書き直してみましょう。Vitest の test.each を使うと、同じテストロジックに対して異なる入力値や期待される出力を簡単に繰り返しテストすることができます。また、各テストでテストケースに値を参照したい場合は、$value と書くことができます。
import { describe, expect, test } from "vitest";
const add = (a: number, b: number) => a + b;
describe("Add", () => {
test.each([
{ a: 1, b: 2, result: 3 },
{ a: 2, b: 3, result: 5 },
{ a: 3, b: 4, result: 7 },
])("adds $a + $b to return $result", ({ a, b, result }) => {
expect(add(a, b)).toBe(result);
});
});
また、もう一つのアプローチとして、describe.each があります。これは複数のテストケースを追加したい場合に便利です。test.each は単一のケースしかできません。
import { describe, expect, test } from "vitest";
const add = (a: number, b: number) => a + b;
describe.each([
{ a: 1, b: 2, result: 3 },
{ a: 2, b: 3, result: 5 },
{ a: 3, b: 4, result: 7 },
])("add($a, $b)", ({ a, b, result }) => {
test(`adds ${a} + ${b} returns ${result}`, () => {
expect(add(a, b)).toBe(result);
});
test("returned value not null", () => {
expect(add(a, b)).not.toBeNull();
});
});
これを実行してみましょう。想定通りにテストケースがパスしました。
$ vitest
add(1, 2) (2)
✓ adds 1 + 2 returns 3
✓ returned value not null
✓ add(2, 3) (2)
✓ adds 2 + 3 returns 5
✓ returned value not null
✓ add(3, 4) (2)
✓ adds 3 + 4 returns 7
✓ returned value not null
Vitest でユニットテストを少しだけクリーンに書くアプローチを紹介しました。Table Driven Test の手法を使うことによって、テストケースを追加しやすくなり、直感的にわかりやすいテストになります。