1、测试基础认知:为什么需要单元测试、TDD与BDD概念、Vue测试生态概览

1.1 我们真的需要单元测试吗?

说实话,我刚入行那会儿,也觉得写测试是浪费时间。

「代码能跑就行,写什么测试?」——这是我当时的真实想法。

直到有一次,我改了一个看似无关紧要的工具函数,结果导致线上订单金额计算全部出错。那晚我盯着屏幕到凌晨三点,一行一行地排查,最后发现是某个边界条件没处理好。嗯,从那以后,我再也不敢轻视单元测试了。

单元测试的核心价值:

  • 提前发现 bug —— 代码还没部署,问题就暴露了
  • 重构有底气 —— 改完代码跑一遍测试,绿了就是没问题
  • 文档即代码 —— 测试用例本身就是最好的使用说明书
  • 倒逼代码质量 —— 为了好测,你会写出更解耦、更干净的代码

你想想看,一个项目动辄几十万行代码,靠人工回归测试?不现实。单元测试就像给你的代码上了份保险,平时觉得贵,真出事才知道值。

1.2 TDD:先写测试,再写代码

TDD,全称 Test-Driven Development,测试驱动开发。说白了就是「红-绿-重构」三步走。

  1. —— 先写一个会失败的测试
  2. 绿 —— 写最简代码让测试通过
  3. 重构 —— 优化代码,保持测试绿色

我个人习惯在写复杂逻辑时用 TDD。比如写一个金额格式化函数:

// 第一步:先写测试(此时会红)
describe('formatCurrency', () => {
  it('应该将数字格式化为人民币', () => {
    expect(formatCurrency(1000)).toBe('¥1,000.00')
  })
  
  it('应该处理负数', () => {
    expect(formatCurrency(-500)).toBe('-¥500.00')
  })
})

// 第二步:写实现代码(变绿)
function formatCurrency(amount) {
  const prefix = amount < 0 ? '-' : ''
  const abs = Math.abs(amount)
  return `${prefix}¥${abs.toLocaleString('zh-CN', { minimumFractionDigits: 2 })}`
}

我的经验:TDD 适合逻辑密集型的函数或组件。但 UI 交互部分,我建议先用 BDD 思路写行为描述,再补单元测试。别死磕 TDD,灵活点。

1.3 BDD:从用户视角出发

BDD,Behavior-Driven Development,行为驱动开发。它和 TDD 最大的区别是:BDD 关注「做什么」,TDD 关注「怎么做」

举个例子,同样是测试一个登录按钮:

  • TDD 风格:测试 login 函数是否返回 token
  • BDD 风格:测试「用户输入正确账号密码后,应该跳转到首页」

BDD 的测试用例读起来更像自然语言。我用 Vue 测试时,经常这样写:

describe('登录组件', () => {
  it('当用户输入正确的账号和密码时,应该显示登录成功', async () => {
    const wrapper = mount(LoginForm)
    await wrapper.find('[data-testid="username"]').setValue('admin')
    await wrapper.find('[data-testid="password"]').setValue('123456')
    await wrapper.find('[data-testid="submit"]').trigger('click')
    
    expect(wrapper.text()).toContain('登录成功')
  })
})

你看,这段代码读起来就像在描述一个用户操作流程。这就是 BDD 的魅力——测试即文档

避坑指南:我曾经在一个项目里过度追求 BDD,把测试写得像小说一样长。结果维护成本极高,每次需求变更都要改一堆测试。记住:BDD 描述行为,但测试粒度还是要控制好,别太粗也别太细。

1.4 Vue 测试生态概览

Vue 的测试生态,说白了就三样东西:

工具 用途 推荐指数
Vitest 单元测试框架(Vite 原生支持) ⭐⭐⭐⭐⭐
Vue Test Utils Vue 组件测试官方工具库 ⭐⭐⭐⭐⭐
Testing Library 更贴近用户行为的测试库 ⭐⭐⭐⭐
Cypress / Playwright 端到端测试(E2E) ⭐⭐⭐⭐

我的推荐组合:

  • 单元测试 + 组件测试:Vitest + Vue Test Utils
  • 集成测试:Testing Library
  • E2E 测试:Playwright(比 Cypress 快,而且和 Vite 更搭)

为什么选 Vitest?

Vitest 和 Vite 共享配置,启动速度极快。我之前用 Jest,每次跑测试都要等好几秒。换成 Vitest 后,几乎是秒启动。而且它兼容 Jest 的 API,迁移成本很低。

1.5 小结:测试不是负担,是投资

写测试确实会多花时间。但你要算一笔账:

  • 一个 bug 在开发阶段发现,修复成本是 1 倍
  • 到了测试阶段发现,成本是 5 倍
  • 上线后才发现,成本是 50 倍

单元测试就是帮你把 bug 扼杀在摇篮里。我个人习惯是:核心逻辑 100% 覆盖,UI 交互覆盖主要流程,边界情况重点照顾。别追求 100% 覆盖率,那没意义。把精力花在刀刃上,才是聪明人的做法。

下一章,我们会搭建 Vue 测试环境,手把手带你跑通第一个测试用例。到时候你就知道,写测试其实没那么难。