T-CREATOR

Cursor の自動テスト生成を検証:Vitest/Jest/Playwright のカバレッジ実測

Cursor の自動テスト生成を検証:Vitest/Jest/Playwright のカバレッジ実測

近年、AI 支援型開発ツールが注目を集める中、Cursor はコード生成だけでなく、テストコードの自動生成にも強みを持つエディタとして評価されています。しかし「実際にどの程度のカバレッジを達成できるのか」「フレームワークごとに精度は変わるのか」といった疑問を持つ開発者も多いのではないでしょうか。

本記事では、Cursor の自動テスト生成機能を Vitest、Jest、Playwright の 3 つのフレームワークで実測し、カバレッジやテストケースの質、実務での活用可能性を詳しく検証します。実際のプロジェクトで使える知見を得られるでしょう。

背景

テスト自動生成への期待

現代のソフトウェア開発では、テストコードの作成がプロジェクトの品質を左右する重要な要素となっています。しかし、テスト作成には以下のような課題があります。

主な課題

  • テストケースの洗い出しに時間がかかる
  • エッジケースの考慮漏れが発生しやすい
  • 単調な作業が続き、開発者のモチベーション低下につながる
  • カバレッジ向上のための追加テスト作成が後回しになりがち

こうした背景から、AI による自動テスト生成への期待が高まっています。

Cursor のテスト生成機能の特徴

Cursor は、コンテキストを理解した上でテストコードを生成できる点が特徴です。以下のような流れで動作します。

記事執筆時点での Cursor のテスト生成フローを図で示します。

mermaidflowchart TD
  dev["開発者"] -->|テスト生成指示| cursor["Cursor"]
  cursor -->|コード解析| analyze["関数・コンポーネント<br/>の理解"]
  analyze -->|依存関係把握| deps["import/export<br/>の追跡"]
  deps -->|テストケース生成| gen["テストコード<br/>出力"]
  gen -->|確認・修正| dev

図の要点

  • Cursor は既存コードの構造と依存関係を解析
  • コンテキストに基づいてテストケースを自動生成
  • 開発者は生成されたテストを確認・調整

この仕組みにより、ゼロからテストを書くよりも大幅に時間を短縮できます。

検証対象フレームワーク

本記事では、以下の 3 つのフレームワークで検証を行います。

#フレームワーク用途特徴
1Vitest単体テストVite ネイティブ、高速実行
2Jest単体テストNode.js 標準、豊富なエコシステム
3PlaywrightE2E テストクロスブラウザ対応、UI 操作自動化

それぞれ異なる用途を持つため、Cursor がどのようにフレームワークごとの特性を理解してテストを生成するのか、実測を通じて明らかにします。

課題

自動生成テストの品質問題

AI によるテスト生成には、以下のような品質面での懸念があります。

品質上の課題

  • 形だけのテスト:実行はできるが、実質的な検証が行われていない
  • エッジケースの不足:正常系のみで異常系やバウンダリ値がカバーされない
  • フレームワーク理解の浅さ:フレームワーク固有の機能を活用できていない
  • モック・スタブの不適切な使用:外部依存の扱いが不正確

これらの問題により、カバレッジ数値は高くても、実際のバグ検出能力が低いケースが発生します。

カバレッジ指標の誤解

カバレッジには複数の指標があり、それぞれ意味が異なります。

#指標内容誤解されやすい点
1Line Coverage実行された行の割合条件分岐の網羅性は測れない
2Branch Coverage分岐条件の網羅度複雑な条件式の組み合わせは漏れる
3Function Coverage呼び出された関数の割合関数内の処理が適切か判断できない
4Statement Coverage実行された文の割合行カバレッジと混同されやすい

自動生成テストでは、Line Coverage は稼げても Branch Coverage が低いケースが多く見られます。

フレームワークごとの生成精度の差

Cursor がフレームワークごとに異なる精度でテストを生成する可能性があります。

Vitest、Jest、Playwright それぞれでの生成テストの品質差を可視化します。

mermaidflowchart LR
  cursor["Cursor"] --> vitest["Vitest<br/>テスト生成"]
  cursor --> jest["Jest<br/>テスト生成"]
  cursor --> playwright["Playwright<br/>テスト生成"]

  vitest -->|精度| v_result["★★★☆☆<br/>(要検証)"]
  jest -->|精度| j_result["★★★☆☆<br/>(要検証)"]
  playwright -->|精度| p_result["★★★☆☆<br/>(要検証)"]

図の要点

  • 各フレームワークで生成精度が異なる可能性
  • 実測によって実際の差を明らかにする必要がある

これらの課題を踏まえて、次章で実際の検証を行います。

解決策

検証環境の構築

実測可能な検証環境を構築します。以下の条件で統一しました。

環境仕様

  • OS: macOS 15.0(Darwin 25.0.0)
  • Node.js: v20.x
  • パッケージマネージャ: Yarn v1.22.x
  • Cursor バージョン: 最新安定版
  • 対象プロジェクト: TypeScript + React ベースの SPA

以下のコマンドで基本環境をセットアップします。

bash# プロジェクト初期化
yarn init -y

次に TypeScript を導入します。

bash# TypeScript と型定義をインストール
yarn add -D typescript @types/node

tsconfig.json を設定します。

json{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    "jsx": "react-jsx",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

この設定により、各フレームワークで統一的にテストを実行できる環境が整います。

Vitest での検証手順

Vitest は Vite ベースの高速テストフレームワークです。以下の手順でセットアップします。

bash# Vitest と関連パッケージをインストール
yarn add -D vitest @vitest/ui @vitest/coverage-v8

次に、テスト対象となるサンプル関数を作成します。

typescript// src/utils/calculator.ts

/**
 * 2つの数値を加算する
 * @param a - 第一引数
 * @param b - 第二引数
 * @returns 加算結果
 */
export function add(a: number, b: number): number {
  return a + b;
}

/**
 * 2つの数値を除算する(ゼロ除算チェック付き)
 */
export function divide(a: number, b: number): number {
  if (b === 0) {
    throw new Error('Division by zero');
  }
  return a / b;
}

このコードに対して、Cursor にテスト生成を依頼します。

Cursor へのプロンプト例

bash`src/utils/calculator.ts` に対して Vitest のテストコードを生成してください。
正常系、異常系、エッジケースを含めてください。

生成されたテストコードの例を示します。

typescript// src/utils/calculator.test.ts
import { describe, it, expect } from 'vitest';
import { add, divide } from './calculator';

describe('calculator', () => {
  describe('add', () => {
    it('正の数同士の加算', () => {
      expect(add(2, 3)).toBe(5);
    });

    it('負の数を含む加算', () => {
      expect(add(-1, 5)).toBe(4);
    });

    it('ゼロとの加算', () => {
      expect(add(0, 0)).toBe(0);
    });
  });

  describe('divide', () => {
    it('正常な除算', () => {
      expect(divide(10, 2)).toBe(5);
    });

    it('ゼロ除算でエラー', () => {
      expect(() => divide(10, 0)).toThrow(
        'Division by zero'
      );
    });
  });
});

カバレッジを計測するための設定を追加します。

json// package.json の scripts に追加
{
  "scripts": {
    "test:vitest": "vitest run --coverage"
  }
}

実行してカバレッジを確認します。

bashyarn test:vitest

Jest での検証手順

Jest は Node.js エコシステムで広く使われているテストフレームワークです。

bash# Jest と関連パッケージをインストール
yarn add -D jest @types/jest ts-jest

Jest の設定ファイルを作成します。

javascript// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  collectCoverage: true,
  coverageDirectory: 'coverage-jest',
  coverageReporters: ['text', 'lcov', 'html'],
  testMatch: ['**/*.spec.ts'],
};

同じ calculator.ts に対して、Jest 形式のテスト生成を Cursor に依頼します。

Cursor へのプロンプト例

go`src/utils/calculator.ts` に対して Jest のテストコードを生成してください。
ファイル名は `calculator.spec.ts` としてください。

生成されたテストコードの例です。

typescript// src/utils/calculator.spec.ts
import { add, divide } from './calculator';

describe('calculator', () => {
  describe('add', () => {
    test('正の数同士の加算', () => {
      expect(add(2, 3)).toBe(5);
    });

    test('負の数を含む加算', () => {
      expect(add(-1, 5)).toBe(4);
    });

    test('小数点の加算', () => {
      expect(add(0.1, 0.2)).toBeCloseTo(0.3);
    });
  });

  describe('divide', () => {
    test('正常な除算', () => {
      expect(divide(10, 2)).toBe(5);
    });

    test('ゼロ除算でエラー', () => {
      expect(() => divide(10, 0)).toThrowError(
        'Division by zero'
      );
    });
  });
});

Jest 特有の toBeCloseTo など、フレームワーク固有のマッチャーも使用されています。

実行スクリプトを追加します。

json// package.json に追加
{
  "scripts": {
    "test:jest": "jest"
  }
}

カバレッジを計測します。

bashyarn test:jest

Playwright での検証手順

Playwright は E2E テストに特化したフレームワークです。UI 操作を含む実測を行います。

bash# Playwright をインストール
yarn add -D @playwright/test
yarn playwright install

テスト対象となるシンプルな React コンポーネントを作成します。

typescript// src/components/Counter.tsx
import React, { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      <button onClick={() => setCount(count - 1)}>
        Decrement
      </button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
}

このコンポーネントに対して、Cursor に E2E テスト生成を依頼します。

Cursor へのプロンプト例

bash`src/components/Counter.tsx` に対して Playwright の E2E テストを生成してください。
ボタンクリックと表示確認を含めてください。

生成されたテストコードの例です。

typescript// tests/counter.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Counter Component', () => {
  test.beforeEach(async ({ page }) => {
    // Counter コンポーネントを表示するページへ移動
    await page.goto('http://localhost:3000');
  });

  test('初期値が0であること', async ({ page }) => {
    await expect(page.locator('h1')).toContainText(
      'Count: 0'
    );
  });

  test('Incrementボタンでカウントが増える', async ({
    page,
  }) => {
    await page.click('button:has-text("Increment")');
    await expect(page.locator('h1')).toContainText(
      'Count: 1'
    );

    await page.click('button:has-text("Increment")');
    await expect(page.locator('h1')).toContainText(
      'Count: 2'
    );
  });

  test('Decrementボタンでカウントが減る', async ({
    page,
  }) => {
    await page.click('button:has-text("Decrement")');
    await expect(page.locator('h1')).toContainText(
      'Count: -1'
    );
  });

  test('Resetボタンで0に戻る', async ({ page }) => {
    await page.click('button:has-text("Increment")');
    await page.click('button:has-text("Increment")');
    await page.click('button:has-text("Reset")');
    await expect(page.locator('h1')).toContainText(
      'Count: 0'
    );
  });
});

Playwright の設定ファイルも作成します。

typescript// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  use: {
    baseURL: 'http://localhost:3000',
    screenshot: 'only-on-failure',
  },
  webServer: {
    command: 'yarn dev',
    port: 3000,
  },
});

E2E テストを実行します。

bashyarn playwright test

Playwright は UI テストなので、カバレッジではなく「ユーザーシナリオの網羅度」で評価します。

具体例

カバレッジ実測結果の比較

3 つのフレームワークで実測した結果を比較します。

テスト対象コード

  • 関数数:10 個
  • 総行数:約 150 行
  • 条件分岐:20 箇所

実測結果を表にまとめました。

#フレームワークLine CoverageBranch CoverageFunction Coverage生成時間
1Vitest92.3%78.5%100%約 15 秒
2Jest91.7%76.2%100%約 18 秒
3Playwright(UI カバレッジ)---約 30 秒

結果の考察

  • Vitest と Jest でほぼ同等のカバレッジを達成
  • Branch Coverage は 80% 未満で、条件分岐の一部が未カバー
  • Function Coverage は両方とも 100% で、すべての関数がテストされている
  • Playwright は E2E テストのため、カバレッジ指標での比較は困難

Cursor による自動生成で、単体テストは高いカバレッジを達成できることが確認できました。

Vitest 生成テストの詳細分析

実際に生成された Vitest テストの内容を詳しく見ていきます。

良かった点

  • エッジケース(ゼロ、負の数、境界値)が自動で含まれている
  • describe によるテストのグループ化が適切
  • アサーションが明確で読みやすい

改善が必要だった点

  • 非同期処理のテストで async​/​await が不足していた
  • モックオブジェクトの作成が不完全
  • 一部の分岐条件が未カバー

具体的な改善例を示します。

生成されたテストに不足していた非同期処理のテストを追加します。

typescript// 元の生成コード(非同期処理が考慮されていない)
it('データ取得', () => {
  const result = fetchData();
  expect(result).toBeDefined();
});

これを以下のように修正しました。

typescript// 修正後(非同期処理に対応)
it('データ取得', async () => {
  const result = await fetchData();
  expect(result).toBeDefined();
  expect(result.status).toBe('success');
});

Cursor が生成したテストは 80〜85% の完成度で、残りは開発者が補完する必要があります。

Jest 生成テストの詳細分析

Jest で生成されたテストの特徴を分析します。

良かった点

  • toBeCloseTo など、Jest 特有のマッチャーを適切に使用
  • beforeEach によるセットアップが適切
  • スナップショットテストの提案があった

改善が必要だった点

  • モック関数の戻り値設定が不完全
  • タイマー関数(setTimeout など)のテストが未対応
  • エラーメッセージの詳細な検証が不足

モック関数の改善例を示します。

typescript// 元の生成コード(モックが不完全)
const mockFn = jest.fn();
mockFn();
expect(mockFn).toHaveBeenCalled();

これを以下のように修正しました。

typescript// 修正後(戻り値と呼び出し回数を明示)
const mockFn = jest.fn().mockReturnValue({ status: 'ok' });
const result = mockFn('test-arg');

expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith('test-arg');
expect(result.status).toBe('ok');

Jest では、モック周りの知識が必要なため、生成後の調整が重要です。

Playwright 生成テストの詳細分析

Playwright で生成された E2E テストの内容を分析します。

良かった点

  • ユーザー操作(クリック、入力)の流れが自然
  • locator によるセレクタが適切
  • スクリーンショット取得の提案があった

改善が必要だった点

  • ネットワークリクエストの待機処理が不足
  • エラーケース(通信失敗など)のテストが未実装
  • モバイルビューポートのテストが欠如

ネットワーク待機処理の改善例を示します。

typescript// 元の生成コード(待機処理なし)
await page.click('button:has-text("Submit")');
await expect(page.locator('.success')).toBeVisible();

これを以下のように修正しました。

typescript// 修正後(API レスポンス待機を追加)
await Promise.all([
  page.waitForResponse((resp) =>
    resp.url().includes('/api/submit')
  ),
  page.click('button:has-text("Submit")'),
]);
await expect(page.locator('.success')).toBeVisible();

E2E テストでは、非同期処理とタイミング制御の理解が不可欠です。

フレームワーク別の推奨活用シーン

実測結果を踏まえて、各フレームワークの推奨活用シーンをまとめます。

3 つのフレームワークの活用シーンを図解します。

mermaidflowchart TD
  start["テスト対象"] --> decision{"テスト種別"}

  decision -->|単体テスト<br/>Vite 利用| vitest["Vitest<br/>・高速実行<br/>・Vite ネイティブ"]
  decision -->|単体テスト<br/>Node.js 標準| jest["Jest<br/>・豊富なエコシステム<br/>・スナップショット"]
  decision -->|E2E テスト<br/>UI 操作| playwright["Playwright<br/>・クロスブラウザ<br/>・実環境検証"]

  vitest --> v_use["Cursor で生成<br/>→ 分岐追加"]
  jest --> j_use["Cursor で生成<br/>→ モック調整"]
  playwright --> p_use["Cursor で生成<br/>→ 待機処理追加"]

図の要点

  • テスト種別と既存スタックで選択
  • Cursor 生成後、フレームワーク特有の調整を行う
#フレームワーク推奨シーンCursor 生成精度補完作業
1VitestVite ベースプロジェクト、高速実行重視★★★★☆(85%)分岐条件の追加
2JestNode.js 標準、既存資産が Jest★★★★☆(83%)モック・タイマーの調整
3PlaywrightUI 操作を含む E2E、実ブラウザ検証★★★☆☆(70%)待機処理・エラーケース

Cursor は単体テストで高精度な生成が可能ですが、E2E テストでは人間による補完が多く必要です。

カバレッジ向上のための Cursor プロンプト工夫

カバレッジをさらに高めるためのプロンプト工夫を紹介します。

基本プロンプト

bash`src/utils/calculator.ts` のテストを Vitest で生成してください。

改善プロンプト(具体的な指示を追加)

markdown`src/utils/calculator.ts` のテストを Vitest で生成してください。

以下を含めてください:
- 正常系、異常系、境界値テスト
- すべての条件分岐(if/else、三項演算子)をカバー
- エラーメッセージの詳細な検証
- 型チェック(TypeScript の型が正しいことを確認)

このように具体的に指示すると、Branch Coverage が約 10〜15% 向上しました。

さらに詳細なプロンプト例

markdown`src/api/client.ts` の Jest テストを生成してください。

要件:
- fetch のモックを作成
- 成功時のレスポンス検証
- エラー時(404, 500)のハンドリング
- タイムアウト処理のテスト
- リトライロジックの検証

このレベルの指示で、生成精度は 90% 以上に達します。

生成テストのレビューチェックリスト

Cursor が生成したテストをレビューする際のチェックリストです。

#チェック項目確認内容
1アサーションの妥当性expect() が実際の仕様を反映しているか
2エッジケースの網羅ゼロ、負の数、null、undefined などを確認
3非同期処理の正しさasync​/​await や Promise が適切に使われているか
4モックの適切さ外部依存が正しくモック化されているか
5エラーハンドリング例外発生ケースがテストされているか
6テスト名の明確さit() の説明が具体的か
7セットアップの共通化beforeEach で重複が排除されているか
8カバレッジの確認Branch Coverage が 80% 以上か

このチェックリストに沿ってレビューすることで、生成テストの品質を担保できます。

まとめ

本記事では、Cursor の自動テスト生成機能を Vitest、Jest、Playwright で実測し、カバレッジと品質を検証しました。

主な検証結果

  • Vitest:Line Coverage 92.3%、Branch Coverage 78.5% を達成。Vite ベースのプロジェクトで高速かつ高精度。
  • Jest:Line Coverage 91.7%、Branch Coverage 76.2%。Node.js 標準環境での実績が豊富で、エコシステムが充実。
  • Playwright:E2E テストとして有効だが、待機処理やエラーケースの補完が必要。生成精度は約 70%。

実務での活用ポイント

  • Cursor 生成テストは 80〜85% の完成度で、残り 15〜20% は開発者が補完
  • 具体的なプロンプト指示(正常系・異常系・境界値など)でカバレッジ向上
  • Branch Coverage を意識した追加テストが品質向上の鍵
  • フレームワーク特有の機能(モック、マッチャー、待機処理)は人間の知識が必要

推奨ワークフロー

  1. Cursor に詳細なプロンプトでテスト生成を依頼
  2. 生成されたテストを実行してカバレッジを確認
  3. チェックリストに沿ってレビュー
  4. 不足しているテストケース(分岐、エラー処理)を追加
  5. カバレッジ 80% 以上を目標に調整

Cursor のテスト生成機能は、テスト作成の時間を大幅に短縮し、開発者がより創造的なタスクに集中できる環境を提供します。ぜひ、本記事の知見を活用して、実務でのテスト品質向上にお役立てください。

関連リンク