Skip to content

测试基础与框架 ​

测试分类 ​

             成本高 · 运行慢 · 信心足
                    ┌─────────┐
                    │  E2E    │
                    │ 测试     │
                    └────┬────┘
                    ┌────┴────┐
                    │  集成   │
                    │  测试   │
                    └────┬────┘
                    ┌────┴────┐
                    │  单元   │
                    │  测试   │
                    └─────────┘
             成本低 · 运行快 · 粒度细
             成本高 · 运行慢 · 信心足
                    ┌─────────┐
                    │  E2E    │
                    │ 测试     │
                    └────┬────┘
                    ┌────┴────┐
                    │  集成   │
                    │  测试   │
                    └────┬────┘
                    ┌────┴────┐
                    │  单元   │
                    │  测试   │
                    └─────────┘
             成本低 · 运行快 · 粒度细
类型范围速度维护成本覆盖率
单元测试函数/组件⚡ 毫秒低逻辑覆盖
集成测试模块交互⏱ 秒级中功能覆盖
E2E 测试完整流程🐢 分钟高场景覆盖

测试框架选型 ​

框架特点适用场景
VitestVite 原生,兼容 Jest API,极速现代项目首选
Jest生态最成熟Webpack 项目
Mocha + Chai灵活可配置自定义需求
PlaywrightE2E 测试,跨浏览器浏览器自动化
CypressE2E 测试,调试体验好E2E / 组件测试
Testing Library行为驱动测试组件测试

AAA 模式 ​

js
// Arrange(准备) → Act(执行) → Assert(断言)
describe('calculateTotal', () => {
  it('should return sum of items', () => {
    // Arrange
    const items = [
      { price: 10, quantity: 2 },
      { price: 5, quantity: 3 },
    ]

    // Act
    const result = calculateTotal(items)

    // Assert
    expect(result).toBe(35)
  })
})
// Arrange(准备) → Act(执行) → Assert(断言)
describe('calculateTotal', () => {
  it('should return sum of items', () => {
    // Arrange
    const items = [
      { price: 10, quantity: 2 },
      { price: 5, quantity: 3 },
    ]

    // Act
    const result = calculateTotal(items)

    // Assert
    expect(result).toBe(35)
  })
})

Mock 与 Stub ​

js
// Mock 函数
const fn = vi.fn()
fn.mockReturnValue(42)
fn.mockImplementation(x => x * 2)

// 验证调用
expect(fn).toHaveBeenCalled()
expect(fn).toHaveBeenCalledWith(1)
expect(fn).toHaveBeenCalledTimes(3)

// Mock 模块
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
}))

// Mock 时间
vi.useFakeTimers()
vi.advanceTimersByTime(1000)
vi.useRealTimers()
// Mock 函数
const fn = vi.fn()
fn.mockReturnValue(42)
fn.mockImplementation(x => x * 2)

// 验证调用
expect(fn).toHaveBeenCalled()
expect(fn).toHaveBeenCalledWith(1)
expect(fn).toHaveBeenCalledTimes(3)

// Mock 模块
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
}))

// Mock 时间
vi.useFakeTimers()
vi.advanceTimersByTime(1000)
vi.useRealTimers()

断言示例 ​

js
// 基础断言
expect(value).toBe(true)            // 严格相等(Object.is)
expect(value).toEqual({ a: 1 })     // 深度相等
expect(value).toBeNull()
expect(value).toBeDefined()
expect(value).toBeUndefined()

// 数字
expect(value).toBeGreaterThan(10)
expect(value).toBeLessThanOrEqual(100)

// 字符串
expect(str).toMatch(/hello/)
expect(str).toContain('world')

// 数组/Set
expect(arr).toContain(1)
expect(arr).toHaveLength(3)

// 异常
expect(() => parse('')).toThrow()
expect(() => parse('')).toThrow('Invalid input')

// 快照
expect(component).toMatchSnapshot()
// 基础断言
expect(value).toBe(true)            // 严格相等(Object.is)
expect(value).toEqual({ a: 1 })     // 深度相等
expect(value).toBeNull()
expect(value).toBeDefined()
expect(value).toBeUndefined()

// 数字
expect(value).toBeGreaterThan(10)
expect(value).toBeLessThanOrEqual(100)

// 字符串
expect(str).toMatch(/hello/)
expect(str).toContain('world')

// 数组/Set
expect(arr).toContain(1)
expect(arr).toHaveLength(3)

// 异常
expect(() => parse('')).toThrow()
expect(() => parse('')).toThrow('Invalid input')

// 快照
expect(component).toMatchSnapshot()