1、上线前一晚的手忙脚乱

周五晚上 11 点,团队准备上线。测试小张在群里喊:"我点了下'忘记密码',页面 500 了!"

开发小李改到凌晨 1 点,修好了"忘记密码"。结果第二天用户反馈:"登录"也不好使了——因为修复时碰到了共用的密码校验逻辑。

这就是没有测试体系的典型:靠人肉点,点不全,改一处崩另一处。

本课解决:

  1. 测试到底在测什么?分几类?
  2. 为什么是"金字塔"而不是"平铺"?
  3. 一个团队该投多少精力在哪种测试上?

2、测试在测什么:三个层次的问题

测试回答的是不同层次的问题:

层次问题谁关心
代码正确性这个函数,输入 X 是不是输出 Y?开发者
组件协作这些模块拼起来,数据还对不对?开发者 / 测试
用户价值用户能不能顺畅完成"下单"这件事?产品 / 测试 / 用户

只测最后一层(人肉点页面):慢、贵、覆盖不全。
只测第一层(只写单元测试):快,但拼起来可能还是坏的。
都要,但比例不同——这就是金字塔。

3、测试金字塔

测试金字塔(Test Pyramid) 是 Mike Cohn 提出的分层模型:

            ▲
           ╱ ╲          端到端测试(E2E)
          ╱───╲         少、慢、贵、接近真实用户
         ╱     ╲
        ╱───────╲       集成测试(Integration)
       ╱         ╲      中等数量、验证模块协作
      ╱───────────╲
     ╱             ╲    单元测试(Unit)
    ╱───────────────╲   多、快、便宜、隔离

核心原则:

越往下的测试越多、越快、越便宜;越往上的越少、越慢、越贵。

为什么不能倒过来("冰淇淋甜筒"反模式)?

    ╲             ╱    ← 大量 E2E:跑 2 小时、经常 flaky、
     ╲           ╱       改一个按钮就红一片,没人敢信
      ╲─────────╱
       ╲       ╱        ← 少量单元:本该最快发现的问题,
        ╲     ╱           却要等到跑完 E2E 才知道
         ╲   ╱
          ╲_╱

甜筒反模式的代价:反馈慢(要等几十分钟)、定位难(红了不知道哪坏了)、脆弱(UI 一改全崩)。团队最后会不信任测试,直接忽略红灯——测试就白写了。

4、每一层测什么、怎么写

① 单元测试(Unit Test)

测:一个函数 / 一个类,隔离掉外部依赖(数据库、网络)。

def test_calc_discount_at_100_returns_10_percent():
    assert calc_discount(100) == 10.0

def test_calc_discount_below_threshold_returns_zero():
    assert calc_discount(50) == 0.0

特点:毫秒级,几百上千个也能秒跑完。这是金字塔的底座,数量最多。

② 集成测试(Integration Test)

测:多个单元协作是否正确——如"业务逻辑 + 真实数据库"、"服务 A 调服务 B"。

def test_create_order_writes_to_database(db):
    order = create_order(db, user_id=1, items=[...])
    row = db.query("SELECT * FROM orders WHERE id=?", order.id)
    assert row is not None

特点:比单元慢(要起数据库/容器),但能发现"接口对不上""事务没提交"这类问题。

③ 端到端测试(E2E / UI Test)

测:从用户视角,走完整流程——打开浏览器、点击、填表、提交、看结果。

def test_user_can_reset_password(page):
    page.goto("/login")
    page.click("text=忘记密码")
    page.fill("#email", "a@b.com")
    page.click("text=发送")
    assert page.text_content(".notice") == "邮件已发送"

特点:最接近真实、最能给信心,但最慢、最贵、最容易碎。所以只覆盖最关键的"黄金路径"(登录、下单、支付……)。

5、测试策略:把金字塔写下来

团队应该有份一页纸的测试策略,回答:

  1. 哪些层我们用?各占比多少?(如 70% 单元 / 20% 集成 / 10% E2E)
  2. 关键路径是哪些?(这些必须有 E2E)
  3. "完成"要不要测试?(Definition of Done,第 17 课)
  4. CI 里跑哪些、多久跑一次?(第 16 课)
  5. 覆盖率的红线是多少?(如新代码 ≥ 80%)

一个务实的参考比例(不是铁律):

单元测试   ~70%   快,覆盖逻辑细节
集成测试   ~20%   验证协作与数据
E2E 测试   ~10%   守关键业务路径
别迷信百分比:重点是"快的多、慢的少,关键路径别漏"。团队舒服、能长期坚持,比数字漂亮重要。

6、更全的测试类型地图

金字塔是按"粒度"分层的。按"测什么性质"还有另一维度:

类型测什么例子
功能测试功能对不对登录能成功
回归测试改完有没有弄坏老功能修了密码,登录还正常吗
冒烟测试最基本功能是否可用部署后能打开首页吗
性能测试快不快、扛不扛得住1000 并发响应时间(第 23 课)
安全测试有没有漏洞SQL 注入、XSS(第 23 课)
探索式测试人主动"找茬"测试员凭经验乱点、找边界
可用性测试好不好用用户能不能找到按钮

探索式测试不能省:自动化测试只能验证"你想到的",探索式测试靠人的创造力发现"你没想到的"(第 6 课的用户视角)。两者互补,不是替代。

7、常见误区

误区问题正解
只写 E2E(甜筒)慢、脆、贵,难维护补底层单元测试,E2E 只守关键路径
追求 100% 覆盖率又累又没收益,测的是"没用的代码"关注关键逻辑覆盖,别为数字而测
测试写完就不管测试腐化,最后全红测试也是代码,要重构、要维护
测的是实现不是行为改个内部写法测试就崩测"对外行为",别测私有实现细节
手工测试全靠人重复劳动、易漏回归用自动化,人做探索式
一句话立场:测试的目的不是"覆盖率数字",而是"改动时的信心"——敢不敢在周一改动核心代码然后放心上线?如果敢,测试就是有效的。

8、动手实验 🎯

任务:为贯穿项目「团队任务清单」设计一份测试策略。

  1. 列出 10 个核心功能(注册、登录、建任务、改任务、删任务、分配、标记完成、筛选、搜索、统计)。
  2. 分层归位:每个功能,标注"单元 / 集成 / E2E"各要测什么,形成一张表。
  3. 写出关键路径(必须有 E2E 的 3 条),并说明理由。
  4. 定比例:给出你团队的金字塔比例,算出 100 个测试怎么分。
  5. 写策略文档(半页),包含"占比 / 关键路径 / DoD / CI 跑法 / 覆盖率红线"。
  6. 对照反模式:检查你的方案有没有掉进"甜筒",如有则调整。
  7. 反思:如果只能保留一层测试,你保留哪层?为什么?

下一课深入金字塔底座——单元测试与 TDD,并给出红-绿-重构的完整实操。

9、今天你带走的三句话

  1. 测试分层:单元多而快、E2E 少而慢;倒过来的"甜筒"会让测试失去信任。
  2. 测试的目的是"改动的信心",不是覆盖率数字。
  3. 自动化 + 探索式互补:机器测你想到的,人找你想不到的。

下一课:单元测试与 TDD。

标签: 软件工程, 项目管理, 开发流程

添加新评论