vitest-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vitest Testing

Vitest 测试

Expert knowledge for testing JavaScript/TypeScript projects using Vitest - a blazingly fast testing framework powered by Vite.
关于使用Vitest测试JavaScript/TypeScript项目的专业指南——Vitest是一款由Vite驱动的超快测试框架。

Quick Start

快速入门

Installation

安装

bash
undefined
bash
undefined

Using Bun (recommended)

Using Bun (recommended)

bun add -d vitest
bun add -d vitest

Using npm

Using npm

npm install -D vitest
undefined
npm install -D vitest
undefined

Configuration

配置

typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,
    environment: 'node', // or 'jsdom'
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      thresholds: { lines: 80, functions: 80, branches: 80 },
    },
    include: ['**/*.{test,spec}.{js,ts,jsx,tsx}'],
  },
})
typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,
    environment: 'node', // or 'jsdom'
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      thresholds: { lines: 80, functions: 80, branches: 80 },
    },
    include: ['**/*.{test,spec}.{js,ts,jsx,tsx}'],
  },
})

Running Tests

运行测试

bash
undefined
bash
undefined

Run all tests (prefer bun)

Run all tests (prefer bun)

bun test
bun test

Watch mode (default)

Watch mode (default)

bun test --watch
bun test --watch

Run once (CI mode)

Run once (CI mode)

bun test --run
bun test --run

With coverage

With coverage

bun test --coverage
bun test --coverage

Specific file

Specific file

bun test src/utils/math.test.ts
bun test src/utils/math.test.ts

Pattern matching

Pattern matching

bun test --grep="calculates sum"
bun test --grep="calculates sum"

UI mode (interactive)

UI mode (interactive)

bun test --ui
bun test --ui

Verbose output

Verbose output

bun test --reporter=verbose
undefined
bun test --reporter=verbose
undefined

Writing Tests

编写测试

Basic Structure

基础结构

typescript
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { add, subtract } from './math'

describe('Math utilities', () => {
  beforeEach(() => {
    // Setup before each test
  })

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

  it('subtracts two numbers correctly', () => {
    expect(subtract(5, 3)).toBe(2)
  })
})
typescript
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { add, subtract } from './math'

describe('Math utilities', () => {
  beforeEach(() => {
    // Setup before each test
  })

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

  it('subtracts two numbers correctly', () => {
    expect(subtract(5, 3)).toBe(2)
  })
})

Parametrized Tests

参数化测试

typescript
describe.each([
  { input: 2, expected: 4 },
  { input: 3, expected: 9 },
])('square function', ({ input, expected }) => {
  it(`squares ${input} to ${expected}`, () => {
    expect(square(input)).toBe(expected)
  })
})
typescript
describe.each([
  { input: 2, expected: 4 },
  { input: 3, expected: 9 },
])('square function', ({ input, expected }) => {
  it(`squares ${input} to ${expected}`, () => {
    expect(square(input)).toBe(expected)
  })
})

Assertions

断言

typescript
// Equality
expect(value).toBe(expected)
expect(value).toEqual(expected)

// Truthiness
expect(value).toBeTruthy()
expect(value).toBeNull()
expect(value).toBeDefined()

// Numbers
expect(number).toBeGreaterThan(3)
expect(number).toBeCloseTo(0.3, 1)

// Strings/Arrays
expect(string).toMatch(/pattern/)
expect(array).toContain(item)

// Objects
expect(object).toHaveProperty('key')
expect(object).toMatchObject({ a: 1 })

// Exceptions
expect(() => throwError()).toThrow('message')

// Promises
await expect(promise).resolves.toBe(value)
await expect(promise).rejects.toThrow()
typescript
// Equality
expect(value).toBe(expected)
expect(value).toEqual(expected)

// Truthiness
expect(value).toBeTruthy()
expect(value).toBeNull()
expect(value).toBeDefined()

// Numbers
expect(number).toBeGreaterThan(3)
expect(number).toBeCloseTo(0.3, 1)

// Strings/Arrays
expect(string).toMatch(/pattern/)
expect(array).toContain(item)

// Objects
expect(object).toHaveProperty('key')
expect(object).toMatchObject({ a: 1 })

// Exceptions
expect(() => throwError()).toThrow('message')

// Promises
await expect(promise).resolves.toBe(value)
await expect(promise).rejects.toThrow()

Mocking

Mock功能

Function Mocks

函数Mock

typescript
import { vi } from 'vitest'

const mockFn = vi.fn()
mockFn.mockReturnValue(42)
mockFn.mockResolvedValue('async result')
mockFn.mockImplementation((x) => x * 2)

expect(mockFn).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledWith('arg')
typescript
import { vi } from 'vitest'

const mockFn = vi.fn()
mockFn.mockReturnValue(42)
mockFn.mockResolvedValue('async result')
mockFn.mockImplementation((x) => x * 2)

expect(mockFn).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledWith('arg')

Module Mocking

模块Mock

typescript
vi.mock('./api', () => ({
  fetchUser: vi.fn(() => ({ id: 1, name: 'Test User' })),
}))

import { fetchUser } from './api'

beforeEach(() => {
  vi.clearAllMocks()
})
typescript
vi.mock('./api', () => ({
  fetchUser: vi.fn(() => ({ id: 1, name: 'Test User' })),
}))

import { fetchUser } from './api'

beforeEach(() => {
  vi.clearAllMocks()
})

Timers

定时器

typescript
beforeEach(() => vi.useFakeTimers())
afterEach(() => vi.restoreAllMocks())

it('advances timers', () => {
  const callback = vi.fn()
  setTimeout(callback, 1000)
  vi.advanceTimersByTime(1000)
  expect(callback).toHaveBeenCalledOnce()
})

it('mocks dates', () => {
  const date = new Date('2024-01-01')
  vi.setSystemTime(date)
  expect(Date.now()).toBe(date.getTime())
})
typescript
beforeEach(() => vi.useFakeTimers())
afterEach(() => vi.restoreAllMocks())

it('advances timers', () => {
  const callback = vi.fn()
  setTimeout(callback, 1000)
  vi.advanceTimersByTime(1000)
  expect(callback).toHaveBeenCalledOnce()
})

it('mocks dates', () => {
  const date = new Date('2024-01-01')
  vi.setSystemTime(date)
  expect(Date.now()).toBe(date.getTime())
})

Coverage

覆盖率

bash
undefined
bash
undefined

Generate coverage report

Generate coverage report

bun test --coverage
bun test --coverage

HTML report

HTML report

bun test --coverage --coverage.reporter=html open coverage/index.html
bun test --coverage --coverage.reporter=html open coverage/index.html

Check against thresholds

Check against thresholds

bun test --coverage --coverage.thresholds.lines=90
undefined
bun test --coverage --coverage.thresholds.lines=90
undefined

Integration Testing

集成测试

typescript
import request from 'supertest'
import { app } from './app'

describe('API endpoints', () => {
  it('creates a user', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'John' })
      .expect(201)

    expect(response.body).toMatchObject({
      id: expect.any(Number),
      name: 'John',
    })
  })
})
typescript
import request from 'supertest'
import { app } from './app'

describe('API endpoints', () => {
  it('creates a user', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'John' })
      .expect(201)

    expect(response.body).toMatchObject({
      id: expect.any(Number),
      name: 'John',
    })
  })
})

Best Practices

最佳实践

  • One test file per source file:
    math.ts
    math.test.ts
  • Group related tests with
    describe()
    blocks
  • Use descriptive test names
  • Mock only external dependencies
  • Use
    concurrent
    tests for independent async tests
  • Share expensive fixtures with
    beforeAll()
  • Aim for 80%+ coverage but don't chase 100%
  • 每个源文件对应一个测试文件:
    math.ts
    math.test.ts
  • 使用
    describe()
    块对相关测试进行分组
  • 使用描述性的测试名称
  • 仅Mock外部依赖
  • 对独立的异步测试使用
    concurrent
    标记
  • 使用
    beforeAll()
    共享开销较大的测试夹具
  • 目标覆盖率达到80%以上,但不必追求100%

See Also

相关链接

  • test-quality-analysis
    - Detecting test smells
  • playwright-testing
    - E2E testing
  • mutation-testing
    - Validate test effectiveness
  • test-quality-analysis
    - 检测测试异味
  • playwright-testing
    - 端到端测试
  • mutation-testing
    - 验证测试有效性