3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Vitest】カバレッジを取得する

3
Posted at

はじめに

この記事では、Vitest でコードカバレッジを取得する方法を解説します。

コードカバレッジは、テストがソースコードのどの程度をカバーしているかを測定する指標です。Vitest は v8 と istanbul の2つのカバレッジプロバイダーをサポートしており、簡単にカバレッジレポートを生成できます。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • VSCode
  • Vite 7.3.1
  • React 19.2.3
  • TypeScript 5.9.3
  • Vitest 4.0.17
  • @vitest/coverage-v8 4.0.17

カバレッジプロバイダーの選択

Vitest では2つのカバレッジプロバイダーから選択できます。

プロバイダー 特徴
v8(デフォルト) Chrome V8 エンジンのネイティブカバレッジ機能を使用。高速で、Vitest 3.2.0 以降は AST ベースの解析により Istanbul と同等の精度
istanbul ソースコードを事前にインストルメント(計測コードを挿入)。長年の実績があり、JavaScript ランタイムを問わず動作

Vitest 3.2.0 以降では v8 プロバイダーでも Istanbul と同等の精度が得られるようになったため、特別な理由がない限り v8(デフォルト)の使用を推奨します。

インストール

カバレッジ機能を使用するには、対応するパッケージをインストールします。

v8 プロバイダーの場合(推奨)

npm install -D @vitest/coverage-v8

istanbul プロバイダーの場合

npm install -D @vitest/coverage-istanbul

初めてカバレッジを実行する際、パッケージがインストールされていなければ Vitest が自動的にインストールを促します。

基本的な設定

vite.config.ts にカバレッジの設定を追加します。

vite.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    coverage: {
      provider: 'v8', // 'v8' または 'istanbul'
      reporter: ['text', 'json', 'html'], // レポート形式
      include: ['src/**/*.{ts,tsx}'], // カバレッジ対象
      exclude: [
        'src/**/*.test.{ts,tsx}',
        'src/**/*.spec.{ts,tsx}',
        'src/test/**',
        'src/main.tsx',
      ],
    },
  },
})

カバレッジの実行

CLI でカバレッジを有効化

npx vitest --coverage

ウォッチモードでカバレッジを有効化

npx vitest --coverage

単発実行でカバレッジを取得

npx vitest run --coverage

成功すると、以下のようなレポートが表示されます。

 ✓ src/components/__tests__/Counter.spec.tsx (4 tests) 234ms

 Test Files  1 passed (1)
      Tests  4 passed (4)
   Start at  10:00:00
   Duration  1.23s

 % Coverage report from v8
-----------------------|---------|----------|---------|---------|-------------------
File                   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------------------|---------|----------|---------|---------|-------------------
All files              |   85.71 |      100 |      80 |   85.71 |
 Counter.tsx           |   85.71 |      100 |      80 |   85.71 | 12-13
-----------------------|---------|----------|---------|---------|-------------------

カバレッジレポートの種類

主なレポーター

レポーター 説明
text ターミナルにテーブル形式で表示(デフォルト)
html HTML 形式のレポートを生成(coverage/index.html
json JSON 形式のレポートを生成
lcov LCOV 形式(CI ツールとの連携に使用)
clover Clover XML 形式
cobertura Cobertura XML 形式

複数のレポーターを使用

vite.config.ts
export default defineConfig({
  test: {
    coverage: {
      reporter: ['text', 'html', 'lcov', 'json'],
    },
  },
})

テスト対象のサンプルコード

カバレッジを計測するサンプルコードを作成します。

src/utils/calculator.ts
export const add = (a: number, b: number): number => {
  return a + b
}

export const subtract = (a: number, b: number): number => {
  return a - b
}

export const multiply = (a: number, b: number): number => {
  return a * b
}

export const divide = (a: number, b: number): number => {
  if (b === 0) {
    throw new Error('Cannot divide by zero')
  }
  return a / b
}

export const calculate = (
  operation: 'add' | 'subtract' | 'multiply' | 'divide',
  a: number,
  b: number
): number => {
  switch (operation) {
    case 'add':
      return add(a, b)
    case 'subtract':
      return subtract(a, b)
    case 'multiply':
      return multiply(a, b)
    case 'divide':
      return divide(a, b)
    default:
      throw new Error(`Unknown operation: ${operation}`)
  }
}

テストコード

src/utils/__tests__/calculator.spec.ts
import { describe, expect, test } from 'vitest'
import { add, subtract, multiply, divide, calculate } from '../calculator'

describe('Calculator', () => {
  describe('add', () => {
    test('2つの数値を足し算できる', () => {
      expect(add(1, 2)).toBe(3)
      expect(add(-1, 1)).toBe(0)
      expect(add(0, 0)).toBe(0)
    })
  })

  describe('subtract', () => {
    test('2つの数値を引き算できる', () => {
      expect(subtract(5, 3)).toBe(2)
      expect(subtract(1, 1)).toBe(0)
      expect(subtract(0, 5)).toBe(-5)
    })
  })

  describe('multiply', () => {
    test('2つの数値を掛け算できる', () => {
      expect(multiply(2, 3)).toBe(6)
      expect(multiply(-2, 3)).toBe(-6)
      expect(multiply(0, 100)).toBe(0)
    })
  })

  describe('divide', () => {
    test('2つの数値を割り算できる', () => {
      expect(divide(6, 2)).toBe(3)
      expect(divide(10, 4)).toBe(2.5)
    })

    test('0で割るとエラーが発生する', () => {
      expect(() => divide(10, 0)).toThrow('Cannot divide by zero')
    })
  })

  describe('calculate', () => {
    test('add 操作で足し算ができる', () => {
      expect(calculate('add', 1, 2)).toBe(3)
    })

    test('subtract 操作で引き算ができる', () => {
      expect(calculate('subtract', 5, 3)).toBe(2)
    })

    test('multiply 操作で掛け算ができる', () => {
      expect(calculate('multiply', 2, 3)).toBe(6)
    })

    test('divide 操作で割り算ができる', () => {
      expect(calculate('divide', 6, 2)).toBe(3)
    })
  })
})

カバレッジしきい値の設定

チームで最低限のカバレッジを維持するために、しきい値を設定できます。しきい値を下回るとテストが失敗します。

vite.config.ts
export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html'],
      // グローバルしきい値
      thresholds: {
        statements: 80,
        branches: 80,
        functions: 80,
        lines: 80,
      },
    },
  },
})

ファイルごとのしきい値

vite.config.ts
export default defineConfig({
  test: {
    coverage: {
      thresholds: {
        // グローバルしきい値
        statements: 80,
        branches: 80,
        functions: 80,
        lines: 80,
        // ファイルごとのしきい値(グローバルを上書き)
        'src/utils/calculator.ts': {
          statements: 100,
          branches: 100,
          functions: 100,
          lines: 100,
        },
      },
    },
  },
})

カバレッジから除外する

設定ファイルで除外

vite.config.ts
export default defineConfig({
  test: {
    coverage: {
      include: ['src/**/*.{ts,tsx}'],
      exclude: [
        'src/**/*.test.{ts,tsx}',
        'src/**/*.spec.{ts,tsx}',
        'src/**/*.d.ts',
        'src/test/**',
        'src/mocks/**',
        'src/main.tsx',
        'src/vite-env.d.ts',
      ],
    },
  },
})

コメントで特定のコードを除外

v8 プロバイダーの場合、/* v8 ignore */ コメントを使用します。

/* v8 ignore next -- @preserve */
function ignoredFunction() {
  // この関数全体がカバレッジから除外される
  console.log('This is ignored')
}

function someFunction(condition: boolean) {
  /* v8 ignore if -- @preserve */
  if (condition) {
    // この if ブロックがカバレッジから除外される
    console.log('Ignored')
  } else {
    console.log('Included')
  }
}

/* v8 ignore next -- @preserve */
const ignoredLine = 'This line is ignored'

istanbul プロバイダーの場合は /* istanbul ignore */ を使用します。

/* istanbul ignore next -- @preserve */
function ignoredFunction() {
  console.log('This is ignored')
}

/* istanbul ignore if -- @preserve */
if (process.env.NODE_ENV === 'development') {
  console.log('Development only')
}

TypeScript を使用する場合、esbuild によるトランスパイル時にコメントが削除されることがあります。-- @preserve を追加することでコメントを保持できます。

Vitest UI でカバレッジを確認

Vitest UI を使用すると、ブラウザ上でカバレッジレポートを視覚的に確認できます。

npm install -D @vitest/ui

UI モードでカバレッジを確認するには、以下の設定が必要です。

vite.config.ts
export default defineConfig({
  test: {
    coverage: {
      enabled: true, // カバレッジを有効化
      reporter: ['text', 'html'], // html レポーターが必要
    },
  },
})

実行コマンド:

npx vitest --ui --coverage

ブラウザが開き、Coverage タブでカバレッジレポートを確認できます。

CI/CD での活用

GitHub Actions での設定例

# .github/workflows/test.yml
name: Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests with coverage
        run: npm run test:coverage

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          files: ./coverage/lcov.info
          fail_ci_if_error: true

package.json のスクリプト例

package.json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "test": "vitest",
    "test:run": "vitest run",
    "test:coverage": "vitest run --coverage",
    "test:ui": "vitest --ui --coverage"
  }
}

すべてのファイルをカバレッジ対象にする

デフォルトでは、テストで読み込まれたファイルのみがカバレッジに含まれます。テストされていないファイルも含めてカバレッジを計測するには、all オプションを使用します。

vite.config.ts
export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      all: true, // テストされていないファイルも含める
      include: ['src/**/*.{ts,tsx}'],
      exclude: [
        'src/**/*.test.{ts,tsx}',
        'src/**/*.spec.{ts,tsx}',
        'src/**/*.d.ts',
      ],
    },
  },
})

v8 と istanbul の使い分け

観点 v8 istanbul
速度 高速(JIT コンパイル時に計測) やや遅い(事前インストルメントが必要)
精度 Vitest 3.2.0 以降は Istanbul と同等 高精度
対応環境 V8 エンジン(Chrome、Node.js)のみ すべての JavaScript ランタイム
推奨用途 一般的なプロジェクト(デフォルト) Firefox や Bun など V8 以外の環境

基本的には v8(デフォルト)を使用し、特定の環境でのみ istanbul を検討してください。

まとめ

この記事では、Vitest でコードカバレッジを取得する方法を解説しました。

Vitest は v8 と istanbul の2つのカバレッジプロバイダーをサポートしています。v8 はデフォルトで有効で、Vitest 3.2.0 以降は AST ベースの解析により Istanbul と同等の精度が得られます。

カバレッジを有効にするには --coverage フラグを使用し、設定ファイルでレポーター、対象ファイル、しきい値などをカスタマイズできます。Vitest UI を使用すれば、ブラウザ上で視覚的にカバレッジレポートを確認することも可能です。

CI/CD パイプラインに組み込むことで、継続的にコードの品質を監視し、チーム全体でカバレッジを維持できます。

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?