SuperAPI AI 工具集

vitest

测试与质量

查看项目

更新于 10-13 21:33

技能介绍

用途

Vitest 是一个由 Vite 驱动的下一代测试框架,专为现代 TypeScript/JavaScript 项目设计。它通过基于 HMR 的测试运行提供高速的测试执行,原生支持 ESM,并具备 TypeScript 优先的设计。它提供与 Jest 兼容的 API,便于已有测试迁移。

主要能力

  • Vite 原生:基于 HMR 的即时测试执行(资料称比 Jest 快 10-100 倍)。
  • TypeScript 优先:内置 TypeScript 支持,无需额外配置。
  • ESM 原生:原生 ES 模块、async/await、顶层 await。
  • Jest 兼容:提供兼容 API,便于迁移。
  • 快照测试:内置快照支持。
  • 组件测试:可集成 React Testing Library、Vue Test Utils。
  • 覆盖率:内置 v8/c8 覆盖率(资料称比 Istanbul 更快)。
  • UI 模式:用于测试调试的 Web UI。

使用方式

安装:

npm install -D vitest
# TypeScript types (usually auto-detected)
npm install -D @vitest/ui  # Optional: UI mode

配置 Vitest(vitest.config.ts):

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,           // Use describe/it/expect globally
    environment: 'node',     // or 'jsdom' for DOM testing
    coverage: {
      provider: 'v8',        // or 'istanbul'
      reporter: ['text', 'json', 'html'],
      exclude: [
        'node_modules/',
        'dist/',
        '**/*.test.ts',
        '**/*.spec.ts',
      ],
    },
    include: ['**/*.{test,spec}.{ts,tsx}'],
    exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'],
  },
});

TypeScript 配置(tsconfig.json):

{
  "compilerOptions": {
    "types": ["vitest/globals"]  // For global describe/it/expect
  }
}

不使用全局变量时可改为 import { describe, it, expect } from 'vitest';。

package.json 脚本:

{
  "scripts": {
    "test": "vitest run",              // CI mode (single run)
    "test:watch": "vitest",            // Watch mode (default)
    "test:ui": "vitest --ui",          // UI mode
    "test:coverage": "vitest run --coverage"
  }
}

核心测试结构使用 describe/it/expect,并支持 beforeEach、afterEach 等钩子:

import { describe, it, expect, beforeEach, afterEach } from 'vitest';

describe('Calculator', () => {
  let calculator: Calculator;

  beforeEach(() => {
    calculator = new Calculator();
  });

  it('adds two numbers correctly', () => {
    const result = calculator.add(2, 3);
    expect(result).toBe(5);
  });

  it('handles negative numbers', () => {
    expect(calculator.add(-5, 3)).toBe(-2);
  });
});

类型测试可使用 expectTypeOf 与 assertType:

import { describe, it, expectTypeOf, assertType } from 'vitest';

interface User {
  id: number;
  name: string;
  email: string;
}

describe('Type Safety', () => {
  it('ensures correct types', () => {
    const user: User = {
      id: 1,
      name: 'Alice',
      email: 'alice@example.com',
    };

    expectTypeOf(user.id).toBeNumber();
    expectTypeOf(user.name).toBeString();
    expectTypeOf(user).toMatchTypeOf<User>();

    assertType<User>(user);
  });
});

Mock 与 Spy 支持 vi.mock、vi.spyOn、vi.fn,并可自定义实现与一次性实现:

import { describe, it, expect, vi } from 'vitest';

vi.mock('./api', () => ({
  fetchUser: vi.fn(),
}));

const mockFn = vi.fn((x: number) => x * 2);
mockFn.mockImplementation((x: number) => x + 10);
mockFn.mockImplementationOnce((x: number) => 100);

定时器模拟可使用 vi.useFakeTimers、vi.advanceTimersByTime、vi.runAllTimersAsync。

React 集成安装:

npm install -D @testing-library/react @testing-library/jest-dom @testing-library/user-event
npm install -D jsdom  # For DOM environment

React 配置示例:

import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
  },
});

setup 文件:

import '@testing-library/jest-dom';
import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import * as matchers from '@testing-library/jest-dom/matchers';

expect.extend(matchers);

afterEach(() => {
  cleanup();
});

React 组件测试与 Hook 测试分别使用 render/screen/userEvent 与 renderHook/act。

Vue 集成安装:

npm install -D @vue/test-utils @vitejs/plugin-vue
npm install -D happy-dom  # Faster alternative to jsdom

Vue 配置示例:

import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  test: {
    globals: true,
    environment: 'happy-dom',
    setupFiles: './src/test/setup.ts',
  },
});

Vue 组件测试使用 mount 与 wrapper.find、wrapper.text、wrapper.emitted 等。

异步测试支持 async/await,并可使用 rejects、resolves 等匹配器。快照测试支持 toMatchSnapshot 与 toMatchInlineSnapshot,并可通过 expect.addSnapshotSerializer 自定义序列化。

覆盖率配置示例:

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html', 'lcov'],
      reportsDirectory: './coverage',
      exclude: [
        'node_modules/',
        'dist/',
        '**/*.test.ts',
        '**/*.spec.ts',
        '**/*.config.ts',
        '**/types/',
      ],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 75,
        statements: 80,
      },
      all: true,  // Include untested files in coverage report
    },
  },
});

运行覆盖率:

npx vitest run --coverage
npx vitest --coverage --ui
npx vitest run --coverage --coverage.lines=90

从 Jest 迁移时,Vitest 提供 Jest 兼容 API,但新代码建议使用 vi 代替 jest。迁移步骤包括卸载旧依赖并安装 Vitest、更新 package.json 脚本、用 vitest.config.ts 替换 jest.config.js、并更新测试文件中的导入与 mock 调用。

高级模式包括 describe.concurrent 并行测试、Test Context 上下文注入、以及 expect.extend 自定义匹配器。

适用场景

Vitest 适用于现代 TypeScript/JavaScript 项目的单元测试与组件测试,尤其是已使用 Vite 的项目;也可用于需要 ESM、TypeScript 类型测试、快照测试、覆盖率统计和可视化 UI 调试的场景;对从 Jest 迁移的团队也可作为替代方案。可用于 React 与 Vue 的组件与 Hook 测试。

限制与注意事项

资料未提供价格、授权协议、支持的运行环境版本或性能数据的第三方验证。CI/CD 中应使用 vitest run 而非默认的 watch 模式(后者会导致 CI 挂起)。最佳实践建议包括:使用 globals: true、优先使用 vi 而非 jest、使用 v8 覆盖率、保持测试独立隔离、mock 外部依赖、使用 TypeScript、在 CI 中使用单次运行模式、利用 UI 模式调试、使用 describe.concurrent 并行独立测试、保持测试聚焦。