すべての組み合わせをflatMapとmapで作成
VitestやJestで「すべての組み合わせ」をテストしたいとき、各パターンを手作業で並べて書いているコードを見かけることがあります。
このようなコードは、手動で書いていると漏れや記述ミスが発生しやすくなります。
すべての組み合わせのテストコードはJavaScriptのflatMapとmapを組み合わせることで手作業で1つずつ書かずに自動生成できます。
組み合わせテストでよくある悩み
例えば、2つの引数を取る関数に対して複数の境界値(-1, 0, 1)を掛け合わせた全パターン(3×3 = 9通り)をテストしたい場合を考えます。
配列をそのまま並べてテストを書く場合、以下のような問題が生じます。
- 手動で並べると要素が増えたときに記述量が増え、組み合わせの漏れに気付きにくい。
- forEachをネストするとVitest (Jest)のtest.for (test.each) 構造から外れてしまい、個別テストとしてのログ可視性が落ちる。
sum.ts
export function sum(a: number, b: number) {
return a + b
}sum.spec.ts
// 以下のように書くと、組み合わせに漏れがあっても気づきにくい
import { expect, test } from 'vitest'
import { sum } from '@/sum'
const cases = [
[-1, -1, -2],
[-1, 0, -1],
[-1, 1, 0],
[0, -1, -1],
[0, 0, 0],
[0, 1, 1],
[1, -1, 0],
[1, 0, 1],
[1, 1, 2],
]
test.for(cases)('sum(%i, %i) -> %i', (a, b, expected) => {
expect(sum(a, b)).toBe(expected)
})テストコードをflatMapとmapで自動生成する
flatMapとmapを組み合わせることで、複数の配列から「すべての組み合わせ」を持ったテスト用オブジェクト配列を1行で構築できます。
sum.spec.ts
import { expect, test } from 'vitest'
import { sum } from '@/sum'
const values = [-1, 0, 1]
// すべての組み合わせ (3 × 3 = 9パターン)
const cases = values.flatMap((a) =>
values.map((b) => ({
a,
b,
expected: a + b,
}))
)
test.for(cases)('sum($a, $b) -> $expected', ({ a, b, expected }) => {
expect(sum(a, b)).toBe(expected)
})この書き方であれば、3つ以上の組み合わせも簡単に書けます。
mode.spec.ts
const types = ['A', 'B']
const statuses = ['active', 'inactive']
const flags = [true, false]
// 2 × 2 × 2 = 8パターンのテストデータが生成される
const cases = types.flatMap((type) =>
statuses.flatMap((status) =>
flags.map((flag) => ({
type,
status,
flag,
}))
)
)
test.for(cases)(
'type: $type, status: $status, flag: $flag',
({ type, status, flag }) => {
// 中略
}
)すべての組み合わせテストのパターン作成が必要になったら、flatMapとmapを使用したパターンを活用してみてください。


