FDE Training · Module 17

17

测试与质量保障 · 让客户敢用、敢上生产

← 返回 FDE 培养总览

模块 17 · 测试与质量保障

本章目标:FDE 交付的东西不能是"我本地跑通了"就完事。客户要的是出了问题能兜住、改了东西不会搞坏老功能。这一章讲 FDE 现场最实用的测试策略:单元测试、接口测试、LLM 应用专属评测、CI 自动化。


写代码 本地跑通 自动测试三层 单元+接口+E2E CI 流水线 提交自动跑测试 上线质量门 测试不过不发版
质量保障闭环:写码 → 三层自动测试 → CI 卡质量门 → 安全发版

17.1 为什么 FDE 必须写测试

很多 FDE 觉得"我就一个人写脚本,测试是浪费时间"。错。原因:

  1. 客户项目改需求频繁,改 A 坏 B 是家常便饭。测试就是你的安全网。
  2. 你不是唯一维护的人——三个月后客户那边的工程师接手,没测试他不敢改。
  3. 上线前手动点一遍要几小时,CI 跑自动测试只要几分钟。

80% 的测试精力应该花在最核心、最容易出 bug 的路径上,不要追求 100% 覆盖率。一个内部 CRUD 后台写一堆测试是过度工程。


17.2 测试金字塔:三层怎么分配精力

层级测什么数量速度例子
单元测试单个函数/类逻辑多(最多)毫秒级金额计算、字符串处理
接口测试API 输入输出中秒级POST /orders 返回 201
E2E 测试完整用户流程少(最少)分钟级用户从注册到下单全流程

金字塔原理:底层多、快、便宜;上层少、慢、贵。别反过来——写一堆慢的 E2E,单元测试一个没有。


17.3 单元测试:给核心逻辑写测试

用 pytest 写一个典型例子:

# calc.py
def calc_order_total(items, tax_rate=0.06):
    subtotal = sum(it["price"] * it["qty"] for it in items)
    tax = subtotal * tax_rate
    return round(subtotal + tax, 2)

# test_calc.py
import pytest
from calc import calc_order_total

def test_basic():
    items = [{"price": 100, "qty": 2}, {"price": 50, "qty": 1}]
    assert calc_order_total(items) == 265.0   # 250 * 1.06 = 265

def test_empty():
    assert calc_order_total([]) == 0

def test_zero_tax():
    items = [{"price": 100, "qty": 1}]
    assert calc_order_total(items, tax_rate=0) == 100

# 跑:pytest test_calc.py -v

写测试的技巧:

  • 测行为不测实现:输入什么 → 输出什么,不要测内部变量。
  • 一个测试一个断言场景:别一个函数里测八件事,挂了不知道哪个错。
  • 边界值必测:空列表、0、负数、超长输入。

17.4 接口测试:给 API 写自动测试

import requests

BASE = "http://localhost:8000"

def test_create_order():
    resp = requests.post(f"{BASE}/orders", json={
        "user_id": 1,
        "items": [{"sku": "A1", "qty": 2}],
    })
    assert resp.status_code == 201
    data = resp.json()
    assert data["order_id"] > 0
    assert data["status"] == "pending"

def test_get_order_not_found():
    resp = requests.get(f"{BASE}/orders/99999")
    assert resp.status_code == 404

def test_unauthorized():
    resp = requests.get(f"{BASE}/orders")
    assert resp.status_code == 401

接口测试要测的关键点:

  • 正常返回 200/201。
  • 参数错返回 400。
  • 不存在返回 404。
  • 未登录返回 401。
  • 权限不够返回 403。

17.5 LLM 应用专属测试:Evals

大模型应用的测试和传统软件不一样——输出不是固定的,你不能 assert 它一定输出某句话。这就是模块 06 讲的 Evals。FDE 现场实用做法:

17.5.1 建一个小评测集

# eval_set.py
EVAL_CASES = [
    {
        "question": "违约金是多少?",
        "context": "合同第3条:违约金为本金的10%",
        "expected_keywords": ["10%", "违约金"],
    },
    {
        "question": "能不能退款?",
        "context": "合同第7条:7天内无理由退款",
        "expected_keywords": ["7天", "退款"],
    },
]

def run_eval():
    passed = 0
    for case in EVAL_CASES:
        answer = ask_rag(case["question"], case["context"])
        # 检查答案里有没有命中关键词
        hits = sum(1 for kw in case["expected_keywords"] if kw in answer)
        if hits == len(case["expected_keywords"]):
            passed += 1
        else:
            print(f"FAIL: {case['question']} -> {answer}")
    print(f"通过率: {passed}/{len(EVAL_CASES)}")

17.5.2 改 Prompt 后必跑回归

每次改 Prompt、换模型、调 RAG 参数,都跑一遍这个评测集。通过率掉了就说明改坏了,别直接上线。


17.6 CI 自动化:提交代码自动跑测试

GitHub Actions 示例:push 代码后自动跑测试,不过就拦住:

# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: {python-version: "3.11"}
      - run: pip install -r requirements.txt pytest
      - run: pytest tests/ -v --tb=short

CI 的意义:测试不过不能合并到主分支、不能部署。把"靠自觉跑测试"变成"不跑就不让过"。


17.7 动手练习(可折叠答案)

练习 1:给"计算订单总价"函数写单元测试,要覆盖哪些场景?

答案思路:

  1. 正常情况:多件商品算总价。
  2. 空购物车:总价 0。
  3. 税率为 0:不打税。
  4. 数量为 0:该商品不计价。
  5. 价格有小数:精度对不对。
练习 2:LLM RAG 应用怎么测"回答得好不好"?

答案思路:

  1. 建评测集:20-50 个典型问题 + 标准答案要点。
  2. 跑一遍,看答案是否命中要点。
  3. 加一个"资料没有的问题"测试,看模型会不会瞎编。
  4. 改 Prompt 后跑回归,通过率不下降才上线。
练习 3:为什么 E2E 测试要少写?

答案思路:

  1. E2E 慢——一个流程跑几分钟,CI 等不起。
  2. E2E 脆——前端改个按钮 id 就挂,维护成本高。
  3. E2E 定位难——挂了不知道是哪层的问题。
  4. 正确姿势:核心流程留 3-5 个 E2E,其余靠单元+接口测试覆盖。

17.8 本章面试题

  1. "测试金字塔是什么?为什么?"→ 答:单元测试多而快(底层),接口测试中等,E2E 少而慢(顶层)。这样测试套件跑得快、维护成本低,又能覆盖关键路径。
  2. "LLM 应用怎么测?不能断言固定输出。"→ 答:建评测集,用关键词命中、参考答案匹配、或用更强的模型当裁判打分。改 Prompt/模型后跑回归,通过率不下降才上线。
  3. "CI 里测试不过怎么办?"→ 答:不能合并、不能部署。先修测试或者修代码,别跳过测试硬发。跳过一次,后面就会跳过无数次。
  4. "追求 100% 覆盖率好不好?"→ 答:不好。覆盖率只是数字,不重要逻辑的测试写得再多也没价值。核心业务路径测好,边缘代码能手动测到就行。

17.9 小结

  • 测试是 FDE 的安全网:改需求不怕、交接不怕、上线有底气。
  • 测试金字塔:多写单元、适量接口、少写 E2E。
  • LLM 应用用 Evals 测:建评测集、关键词/裁判打分、改完跑回归。
  • CI 把测试变成强制门槛:不过就不让发版。
  • 不要追求 100% 覆盖率,把核心路径测好就够。
本页由 FDE 培养课程文档生成,完整课程见 FDE 培养 · 课程总览。