前端测试:别为了100%覆盖率而写测试,那是自欺欺人
前端测试常走两个极端:要么完全不测,上线随缘;要么为了覆盖率,测了等于没测(比如测个 今天我们用“测试金字塔”模型,帮你理清单元测试、组件测试、E2E测试的分工。看完你会知道:哪部分代码必须测,哪部分可以跳过,哪部分用哪个工具。 比例大概是:单元测试占70%,集成测试20%,E2E 10%。不是死规定,但原则:底层测试成本低,多写;顶层测试维护成本高,只写关键路径。 单元测试的目标:给定输入,输出是否正确。不关心函数内部怎么实现的,只关心结果。 适合测的: 不适合测的(测了也白测): 工具:Jest + Vitest(Vite项目推荐Vitest)。 例子: 黄金法则:如果重构代码不破坏测试,说明你测的是行为,不是实现。 组件测试(React Testing Library / Vue Test Utils)的目标:模拟用户行为,检查组件渲染和交互是否正确。不关心DOM结构细节,只关心用户能看到什么、能做什么。 适合测的: 不适合测的: 工具:React Testing Library + Jest(官方推荐),Vue Test Utils + Vitest。 例子(React Testing Library): 原则:测用户能看到的东西,不要测内部实现。 E2E测试模拟真实浏览器,跑完整的用户流程。它最像真实用户,但也最慢、最脆弱(网络波动、页面改动容易挂)。 适合测的(3-5个核心流程): 不适合测的: 工具:Cypress(最友好)、Playwright(更可靠)、Puppeteer(较底层)。 例子(Cypress): 维护技巧:给关键元素加上 很多团队追求100%覆盖率,结果工程师花大量时间测无关紧要的代码(比如测Redux的action creator是个纯对象)。覆盖率工具(Istanbul)只能告诉你“哪些代码没执行过”,不能告诉你“没测到的重要逻辑”。有时100%覆盖率,却漏掉了一个关键的空值判断。 正确的覆盖率指标: 日常开发:单元测试 + 组件测试在CI里跑(每次push)。E2E测试单独流水线,部署前跑一次(因为慢)。 测试是手段,不是目的。目的是信心:当你改完代码,测试全绿,你能放心上线。 别买一大堆没用的险,也别裸奔。你写了测试,覆盖率100%,感觉稳了。结果上线后,用户点了个按钮,页面直接白屏。你纳闷:覆盖率不是100%吗?因为你测的都是“天气好不好”,没测“会不会地震”。今天我们就来聊聊前端测试的正确姿势——怎么测才能真的有用,而不是为了指标好看写一堆废话。
前言
1 + 1 = 2)。真正有效的测试,不是越多越好,而是该测的测,不该测的别浪费生命。一、测试金字塔:三分天下,各司其职
/\
/E2E\ ← 少而精,关键路径
/------\
/集成测试\ ← 中等,组件间交互
/----------\
/ 单元测试 \ ← 多而快,纯逻辑
/--------------\二、单元测试:测逻辑,不测实现细节
calculateDiscount(price, level))。formatDate、parseQuery)。// 要测的函数
function formatPrice(price, currency = '¥') {
return `${currency}${price.toFixed(2)}`;
}
// 测试
test('格式化价格', () => {
expect(formatPrice(10.5)).toBe('¥10.50');
expect(formatPrice(10.5, '$')).toBe('$10.50');
});三、组件测试:测交互,不测样式
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('点击按钮增加计数', () => {
render(<Counter />);
const button = screen.getByText('增加');
fireEvent.click(button);
expect(screen.getByText('计数: 1')).toBeInTheDocument();
});四、E2E测试:测关键用户旅程,不测所有交互
describe('用户登录', () => {
it('输入正确账号密码后跳转到首页', () => {
cy.visit('/login');
cy.get('[data-cy=username]').type('user@example.com');
cy.get('[data-cy=password]').type('password123');
cy.get('[data-cy=submit]').click();
cy.url().should('include', '/dashboard');
cy.contains('欢迎回来', { timeout: 10000 });
});
});data-cy属性,避免改样式或文本时测试挂掉。五、测试覆盖率的谎言
六、组合策略:一个电商网站的例子
七、测试不是银弹,别为了写而写
八、总结:测试就像买保险