第20章:テストを速くするコツ(並列・分離・再利用)🏎️🧪✨
テストって、速いほど続きます🙂 逆に遅いと「あとでやるか…」になって、だんだん回らなくなるんだよね…🥺
この章は、**「遅い→速い→気持ちいい」**を作る章です💨💨
この章でできるようになること ✅✨
- 🕵️♂️ どこが遅いかを見つけられる(計測)
- 🧪 ユニットと統合テストを分けて普段の実行を爆速にする(分離)
- 🧵 並列実行でCPUを働かせる(並列)
- ♻️ 重い準備を再利用してムダを減らす(再利用)
- 🧊 キャッシュや差分実行で「変更した分だけ」回す(再利用その2)
1) まずは「どこが遅い?」を可視化しよう 👀🔎
速くする前に、遅い犯人を特定します🕵️♀️✨ おすすめの見える化はこのへん👇
① “遅いテスト”を目立たせる 🐢💥
Vitest は「遅いテスト」を検出する閾値を持てます(slowTestThreshold)🧪✨
vitest.config.ts に足してみよう👇
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
slowTestThreshold: 200, // 200ms超えたら「遅いよ!」って目立つ(好みで調整)
},
});
② メモリで遅くなってない?(地味に多い)🧠🔥
重いテストは、メモリ(ヒープ)増えがちです。 Vitest には 各テストのヒープサイズ表示があります👇 (vitest.dev)
vitest run --logHeapUsage
2) 速くする最大のコツ:テストを「分離」する ✂️🚀
ここが一番効くことが多いです🙂✨
- ✅ ユニットテスト:普段はこれだけ回す(爆速)
- 🧱 統合テスト(DB/HTTP/Redisなど):必要なときだけ回す(重いから)
おすすめ構成 📁✨
tests/unit/**…ユニットtests/integration/**…統合(DBあり等)
そして npm scripts をこう分ける👇(名前が大事!覚えなくて良くなる)🧠✨
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:unit": "vitest run tests/unit",
"test:unit:watch": "vitest tests/unit",
"test:integration": "vitest run tests/integration"
}
}
Vitest は watch がデフォルトで、vitest run は watchなしの単発実行です。 (vitest.dev)
つまり普段は npm test(watchで快適)、CIは npm run test:run(単発)みたいにできるよ😄
3) 並列で速くする:3つのレバーを押す 🧵⚙️⚡
レバーA:テストファイルは基本「並列」になってる ✅
Vitest は テストファイル単位で並列実行が基本です。 (vitest.dev)
止めたいときは fileParallelism: false(=ほぼ直列)もできます。 (vitest.dev)
レバーB:ワーカー数(maxWorkers)を調整する 🧑🏭👷♀️
CPUを活かすならここ!
CLI でも設定でもOKで、--maxWorkers が使えます。 (vitest.dev)
例:CPUの半分だけ使う👇
vitest run --maxWorkers=50%
「PCが爆熱🔥」「他作業が重い😵」ってときは下げると快適になるよ🙂
レバーC:pool を変える(forks ↔ threads)🧵🔁
Vitest はデフォで forks(別プロセス)だけど、threads(worker_threads)にすると速くなるケースがあります⚡
公式も “さらに速くするなら threads を検討” って言ってます(ただし相性注意)。 (vitest.dev)
vitest run --pool=threads
4) “同じファイル内”も並列にしたい?(ただし効く条件あり)🏃♂️🏃♀️💨
ポイント:Vitest は **ファイル内のテストは基本「順番」**です。
でも concurrent で「同時実行グループ」にできます🙂 (vitest.dev)
import { test, expect } from "vitest";
test.concurrent("A", async () => {
// await する重い処理があると効きやすい
expect(1).toBe(1);
});
test.concurrent("B", async () => {
expect(2).toBe(2);
});
さらに “同時に走らせる数” は maxConcurrency で調整できます。 (vitest.dev)
⚠️注意:
- 同期処理ばっかりだと、同時実行してもあまり速くならないことがあります(CPUが1本で詰まる)🙂
- DB みたいな 共有資源があると壊れやすいので、統合テストでは慎重に🙏
5) 再利用で速くする:準備を “毎回やらない” ♻️🍱
重い原因、だいたいここ👇
- DBの初期化
- seed投入
- サーバ起動
- 大量import(起動が遅い)
① setupFiles と globalSetup の使い分け 🧩
setupFiles:各テストファイルの前に毎回走る(同じプロセス) (vitest.dev)globalSetup:全体で1回だけ(ワーカー作成前)走る(重い準備向き) (vitest.dev)
例えば「統合テストの前にDBコンテナが起動してることを保証」みたいなのは、globalSetup 側に寄せるとムダが減りやすいよ🙂✨
② 差分だけテストする(体感めちゃ効く)✂️⚡
--changed:変更されたファイルに関連するテストだけ回す (vitest.dev)vitest related:指定ソースに関連するテストだけ回す(lint-stagedとも相性◎) (vitest.dev)
例👇
vitest --changed
vitest related --run src/index.ts
③ キャッシュで “次の実行” を速くする 🧊💨
experimental.fsModuleCache は 再実行時にモジュールをファイルシステムにキャッシュできます。 (vitest.dev)
vitest --experimental.fsModuleCache
キャッシュを消したいときは👇(次は遅くなるよ、って注意も公式に書いてある) (vitest.dev)
vitest --clearCache
6) “禁断の奥義”:isolate を切って速くする(ただし副作用に注意)⚠️🧨
Vitest は **各テストファイルを隔離(isolate)**して、ファイル間の汚染を防ぎます。 (vitest.dev) でもこの隔離が、プロジェクトによっては 遅さの原因になります🥺
公式は「副作用に頼らないなら、isolateを切ると速くなる」って言ってます。 (vitest.dev)
vitest run --no-isolate
⚠️注意ポイント(ここ超大事)
- グローバル変数とか、環境汚染するテストがあると壊れます💥
- まずは unit だけで試すのがおすすめ🙂
7) CIでさらに速く:シャーディング(分割実行)⚙️🧩🚀
テストが増えたら、CIで 分割して同時実行が効きます。
Vitest の --shard は、テスト全体を <index>/<count> に分割して実行できます。 (vitest.dev)
vitest run --shard=1/3
vitest run --shard=2/3
vitest run --shard=3/3
watch とは一緒に使えない点も公式に明記されてるよ🙂 (vitest.dev)
8) ミニ課題 🎯💪(30〜60分)
課題A:遅いテストを炙り出す 🐢🔥
slowTestThresholdを 200ms に設定npm run test:unitを実行- “遅いテストTop3” をメモ📝
課題B:分離で爆速ループを作る ✂️⚡
tests/unitとtests/integrationを作る- scripts を分ける(
test:unit/test:integration) - 普段は
test:unit:watchだけ回す🌀
課題C:並列の効き具合を体感する 🧵💨
vitest run --maxWorkers=50%vitest run --maxWorkers=100%- 体感&時間を比べる⌛(熱くなりすぎたら下げてOK🔥)
9) よくある詰まり 🧯😵💫
-
😭 並列にしたらたまに落ちる → 共有資源(DB/同じポート/同じファイル)を触ってる合図。統合テストは
maxWorkers=1で走らせるのも全然アリ🙂 -
🧨 --no-isolate で壊れた → テストが状態を片付けてない可能性大。
beforeEach/afterEachで初期化・後片付けを徹底しよう🧹 -
🐌 最初の起動が遅い →
--changed/related/fsModuleCacheが効くこと多いよ⚡ (vitest.dev)
10) AIで時短 🤖✨(使いどころが超ある)
ここだけはガンガンAI使ってOKです😄 (たとえば GitHub の Copilot や OpenAI 系のコーディング支援)
そのまま投げてOKなプロンプト例 🪄
- 「この
vitest.config.tsを、unit は速く、integration は安全に(直列寄り)実行できるように scripts と設定案を出して」 - 「遅いテストTop3を、テストの意図を壊さずに速くする改善案を3パターン出して(副作用注意)」
- 「
--no-isolateを試したい。壊れやすいパターン(グローバル汚染)を検出する観点チェックリスト作って」
まとめ 🎁✨
テスト高速化は、だいたいこの順で勝てます👇
- 👀 可視化(遅い場所を特定)
- ✂️ 分離(unit と integration)
- 🧵 並列(maxWorkers / pool / concurrent)
- ♻️ 再利用(globalSetup / changed / related / cache)
- ⚠️ 最後に禁断(no-isolate)
次の章(第21章)では、Lint と Format を混ぜて地獄を見ない方法に進むよ🧹✨