全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-20 10 分钟 ✍️ juanwangdev

Vue大型项目测试策略(单元测试、E2E测试)

大型Vue项目需建立完整的测试体系,下面梳理核心测试策略。

测试框架选型

技术栈组合

测试类型工具用途
单元测试Vitest工具函数、composables、store
组件测试@vue/test-utils组件渲染与交互
E2E测试Cypress/Playwright完整业务流程

单元测试

工具函数测试

JavaScript
// tests/unit/utils/format.test.js
import { describe, it, expect } from 'vitest'
import { formatDate, formatCurrency } from '@/utils/format'

describe('formatDate', () => {
  it('should format date correctly', () => {
    const date = new Date('2026-05-20')
    expect(formatDate(date, 'YYYY-MM-DD')).toBe('2026-05-20')
  })
  
  it('should return empty string for invalid date', () => {
    expect(formatDate(null)).toBe('')
  })
})

describe('formatCurrency', () => {
  it('should format number to currency', () => {
    expect(formatCurrency(1000.5)).toBe('¥1,000.50')
  })
})

Composables测试

JavaScript
// tests/unit/composables/useCounter.test.js
import { describe, it, expect } from 'vitest'
import { useCounter } from '@/composables/useCounter'

describe('useCounter', () => {
  it('should increment counter', () => {
    const { count, increment } = useCounter()
    increment()
    expect(count.value).toBe(1)
  })
  
  it('should decrement counter', () => {
    const { count, decrement } = useCounter(10)
    decrement()
    expect(count.value).toBe(9)
  })
})

组件测试

基础组件测试

JavaScript
// tests/components/BaseButton.spec.js
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import BaseButton from '@/components/base/BaseButton.vue'

describe('BaseButton', () => {
  it('should render button with text', () => {
    const wrapper = mount(BaseButton, {
      slots: { default: 'Click Me' }
    })
    expect(wrapper.text()).toBe('Click Me')
  })
  
  it('should emit click event', async () => {
    const wrapper = mount(BaseButton)
    await wrapper.trigger('click')
    expect(wrapper.emitted('click')).toHaveLength(1)
  })
  
  it('should be disabled when prop is true', () => {
    const wrapper = mount(BaseButton, {
      props: { disabled: true }
    })
    expect(wrapper.attributes('disabled')).toBeDefined()
  })
})

Mock策略

JavaScript
// tests/components/UserCard.spec.js
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import UserCard from '@/components/business/UserCard.vue'
import * as userApi from '@/api/user'

// Mock API
vi.mock('@/api/user', () => ({
  userApi: {
    getById: vi.fn().mockResolvedValue({ id: 1, name: 'Test' })
  }
}))

describe('UserCard', () => {
  it('should fetch user data on mount', async () => {
    const wrapper = mount(UserCard, {
      props: { userId: 1 }
    })
    await wrapper.vm.$nextTick()
    expect(userApi.userApi.getById).toHaveBeenCalledWith(1)
  })
})

E2E测试

Cypress示例

JavaScript
// tests/e2e/specs/login.cy.js
describe('Login Flow', () => {
  beforeEach(() => {
    cy.visit('/login')
  })
  
  it('should login successfully', () => {
    cy.get('[data-testid="username"]').type('admin')
    cy.get('[data-testid="password"]').type('password123')
    cy.get('[data-testid="login-btn"]').click()
    
    cy.url().should('include', '/dashboard')
    cy.get('[data-testid="user-avatar"]').should('be.visible')
  })
  
  it('should show error for invalid credentials', () => {
    cy.get('[data-testid="username"]').type('wrong')
    cy.get('[data-testid="password"]').type('wrong')
    cy.get('[data-testid="login-btn"]').click()
    
    cy.get('[data-testid="error-msg"]')
      .should('be.visible')
      .and('contain', '用户名或密码错误')
  })
})

测试覆盖率要求

覆盖率指标

JavaScript
// vitest.config.js
export default defineConfig({
  test: {
    coverage: {
      provider: 'istanbul',
      reporter: ['text', 'html', 'lcov'],
      thresholds: {
        branches: 70,
        functions: 80,
        lines: 80,
        statements: 80
      },
      include: ['src/**/*.{js,ts,vue}'],
      exclude: ['src/main.js', 'src/router/**']
    }
  }
})

测试金字塔

层级占比速度成本
单元测试60%
组件测试25%
E2E测试15%

要点总结

  • 测试体系采用Vitest + @vue/test-utils + Cypress组合
  • 工具函数与composables优先写单元测试
  • 组件测试重点验证渲染结果与用户交互
  • E2E测试覆盖核心业务流程,如登录、下单
  • API调用使用vi.mock隔离外部依赖
  • 测试覆盖率要求行覆盖率80%+,分支覆盖率70%+
  • 遵循测试金字塔,底层多顶层少

存放路径: articles/VUE/专家/大型项目架构分层设计/测试策略(单元测试、E2E测试).md

📝 发现内容有误?点击此处直接编辑

← 上一篇 Vue大型项目构建与部署配置
下一篇 → Vue大型项目组件分层与复用策略
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库