vitest-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVitest 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
undefinedbash
undefinedUsing Bun (recommended)
Using Bun (recommended)
bun add -d vitest
bun add -d vitest
Using npm
Using npm
npm install -D vitest
undefinednpm install -D vitest
undefinedConfiguration
配置
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
undefinedbash
undefinedRun 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
undefinedbun test --reporter=verbose
undefinedWriting 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
undefinedbash
undefinedGenerate 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
undefinedbun test --coverage --coverage.thresholds.lines=90
undefinedIntegration 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.tsmath.test.ts - Group related tests with blocks
describe() - Use descriptive test names
- Mock only external dependencies
- Use tests for independent async tests
concurrent - Share expensive fixtures with
beforeAll() - Aim for 80%+ coverage but don't chase 100%
- 每个源文件对应一个测试文件:→
math.tsmath.test.ts - 使用块对相关测试进行分组
describe() - 使用描述性的测试名称
- 仅Mock外部依赖
- 对独立的异步测试使用标记
concurrent - 使用共享开销较大的测试夹具
beforeAll() - 目标覆盖率达到80%以上,但不必追求100%
See Also
相关链接
- - Detecting test smells
test-quality-analysis - - E2E testing
playwright-testing - - Validate test effectiveness
mutation-testing
- - 检测测试异味
test-quality-analysis - - 端到端测试
playwright-testing - - 验证测试有效性
mutation-testing