JestとVitest、どっちを選ぶ?プロジェクト別おすすめテストフレームワークの選び方

目次

「テスト入れたいけど、JestとVitestどっちがいいの?」

新しいプロジェクトにテストを導入しようと調べたら、Jestの記事もVitestの記事も出てくる。「Vitestの方が速いらしい」「でもJestの方が情報が多い」「結局どっち?」と迷って、テスト導入自体が後回しになる。こんなパターン、あるあるですよね。

結論から言うと、どちらも優秀なテストフレームワークで「間違い」はありません。ただし、プロジェクトの技術スタックによって「より自然な選択肢」があります。本記事では、JestとVitestの違いをサクッと比較した上で、プロジェクト別の選び方と、最低限押さえたいテストパターンを紹介します。

JestとVitestって何が違う? ― 30秒でわかる比較

項目 Jest Vitest
開発元 Meta(Facebook) Viteチーム
初リリース 2014年 2022年
実行速度 普通〜やや遅い 高速(Viteのビルドパイプラインを利用)
設定の手軽さ ゼロコンフィグ(ただしTS/ESMは設定が必要) Viteプロジェクトならほぼゼロコンフィグ
ESM対応 実験的(設定が面倒) ネイティブ対応
TypeScript対応 ts-jest@swc/jestが必要 標準で対応
APIの互換性 Jest互換API(移行しやすい)
エコシステム 巨大(情報量・プラグイン豊富) 急成長中(Viteエコシステムと統合)
ウォッチモード あり デフォルトでウォッチモード(高速HMR連動)

ざっくり言えば、Jestは「安定・実績・情報量」、Vitestは「速度・モダン対応・Viteとの親和性」が強みです。

Jestが向いているプロジェクト

  • Create React App(CRA)ベースのプロジェクト:CRAにはJestが標準搭載されている。わざわざ外す理由がない
  • Node.js / NestJSのバックエンド:Viteを使わないサーバーサイドでは、Jestの方が設定がシンプル
  • 既存のテストスイートがJestで書かれている:数百〜数千のテストを移行するコストは無視できない
  • チームにJestの経験者が多い:学習コストゼロで始められる

Jestは10年以上の歴史があり、Stack OverflowやZennで困った時に日本語の情報がすぐ見つかるのも大きなメリットです。

Vitestが向いているプロジェクト

  • Viteベースのプロジェクト(React + Vite、Vue + Vite、SvelteKit等)vite.config.tsの設定をそのまま流用できるので、エイリアスやプラグインの二重管理が不要
  • Next.js App Router(新規プロジェクト):ESMやTypeScriptをネイティブで扱えるVitestの方が設定のハマりが少ない
  • テスト実行速度を重視する:大規模プロジェクトでCIの時間が気になるなら、Vitestの速度差は効いてくる
  • 新規プロジェクトで技術的負債がない:ゼロから始めるなら、よりモダンな選択肢を選ばない理由がない

公式ドキュメント(Vitest公式)も分かりやすく整備されています。

迷ったらこのフローチャート

Q1. ビルドツールにViteを使っている?
  → YES → Vitest
  → NO ↓

Q2. 既存のJestテストが大量にある?
  → YES → Jest(無理に移行しない)
  → NO ↓

Q3. Node.js / NestJSのバックエンド?
  → YES → Jest(安定・実績重視)
  → NO ↓

Q4. 新規プロジェクト?
  → YES → Vitest(モダン・高速)
  → NO → 現状維持(動いてるものは触らない)

移行は大変? JestからVitestへの乗り換えコスト

VitestはJest互換のAPIを提供しているため、多くのテストコードはそのまま動きます。主な変更点は設定ファイルとインポートだけです。

# Jestをアンインストール、Vitestをインストール
npm uninstall jest ts-jest @types/jest
npm install -D vitest
// vite.config.ts に追加するだけ
/// 
import { defineConfig } from 'vite';

export default defineConfig({
  test: {
    globals: true,       // describe, it, expectをimportなしで使える
    environment: 'jsdom', // DOM操作が必要な場合
  },
});
// package.json
{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run"
  }
}

テストコード自体はdescribeitexpectがそのまま使えるので、ほとんど書き換え不要。ハマりやすいのはjest.mock()vi.mock()に変える程度です。

// Jest
jest.mock('./api');
const mockFn = jest.fn();

// Vitest(viをimportするだけ)
import { vi } from 'vitest';
vi.mock('./api');
const mockFn = vi.fn();

実践:最低限押さえたいテストパターン3選

JestでもVitestでもAPIはほぼ同じなので、両方で使えるコード例を紹介します。

パターン1:純粋な関数のユニットテスト

まずはこれだけでいいので書き始めましょう。副作用のない関数は最もテストしやすい対象です。

// lib/tax.ts
export function calcTaxIncluded(price: number, taxRate = 0.1): number {
  return Math.floor(price * (1 + taxRate));
}

// lib/tax.test.ts
import { calcTaxIncluded } from './tax';

describe('calcTaxIncluded', () => {
  it('税率10%で税込価格を計算する', () => {
    expect(calcTaxIncluded(1000)).toBe(1100);
  });

  it('小数点以下を切り捨てる', () => {
    expect(calcTaxIncluded(999)).toBe(1098);
  });

  it('税率を指定できる', () => {
    expect(calcTaxIncluded(1000, 0.08)).toBe(1080);
  });
});

パターン2:API呼び出しのモックテスト

外部APIに依存する処理は、モックで切り離してテストします。

// services/user.ts
export async function getUser(id: string) {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error('User not found');
  return res.json();
}

// services/user.test.ts
import { getUser } from './user';
import { vi } from 'vitest'; // Jestならこの行を削除

// fetchをモック
global.fetch = vi.fn(); // Jestなら jest.fn()

describe('getUser', () => {
  it('ユーザー情報を返す', async () => {
    (fetch as any).mockResolvedValueOnce({
      ok: true,
      json: async () => ({ id: '1', name: '田中' }),
    });

    const user = await getUser('1');
    expect(user.name).toBe('田中');
  });

  it('404でエラーを投げる', async () => {
    (fetch as any).mockResolvedValueOnce({ ok: false });

    await expect(getUser('999')).rejects.toThrow('User not found');
  });
});

パターン3:Reactコンポーネントのテスト

Testing Libraryと組み合わせて、ユーザー操作をシミュレートします。

# Testing Libraryのインストール
npm install -D @testing-library/react @testing-library/jest-dom jsdom
// components/Counter.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { Counter } from './Counter';

describe('Counter', () => {
  it('ボタンを押すとカウントが増える', () => {
    render();

    const button = screen.getByRole('button', { name: '+1' });
    fireEvent.click(button);

    expect(screen.getByText('1')).toBeInTheDocument();
  });
});

Testing LibraryのrenderscreenfireEventはJestでもVitestでも同じように使えます。テストフレームワークを変えても、テストの書き方自体は変わらないのがTesting Libraryの良いところです。

テスト導入をさらに進める関連記事

テストフレームワークを選んだら、開発環境やCI/CDの整備もあわせて進めましょう。

開発効率化・コード品質

Git・CI/CD

まとめ:迷ったら「Viteを使ってるならVitest、それ以外はJest」

本記事のポイントを整理します。

  • Jestは安定・実績・情報量が強み。CRA、Node.js/NestJS、既存プロジェクトに最適
  • Vitestは速度・モダン対応・Viteとの親和性が強み。Viteベースの新規プロジェクトに最適
  • APIはほぼ互換jest.fn()vi.fn()程度の差で、移行コストは低い
  • どちらを選んでもテストの書き方は同じ。Testing Libraryとの組み合わせも共通
  • 最低限3パターンを押さえる:純粋関数のユニットテスト、APIモック、コンポーネントテスト

テストフレームワーク選びで悩む時間よりも、1つでもテストを書き始める方がはるかに価値があります。完璧なカバレッジを目指さなくていい。まずは一番壊れやすい関数に1本テストを書く。その1本が、深夜の障害対応からあなたを救ってくれるかもしれません。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次