بنقرة واحدة
testing
需为代码写测试或改进脆弱测试时。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
需为代码写测试或改进脆弱测试时。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
需求模糊、含隐藏假设或 X-Y problem,需先澄清再动手时。
审查代码(自己的或别人的),需有重点、分层次地看时。
Git 改动需编写规范提交信息时。
遇到 bug、报错、崩溃或行为异常,需定位根因时。
设计或改进错误处理与日志时。
在 Lion-Skills 仓库创建或修改 skill 时。
| name | testing |
| description | 需为代码写测试或改进脆弱测试时。 |
写能真正抓住 bug、且不脆弱(改实现不会无端崩)的测试。核心:测试是行为的契约,不是"代码的镜像"——测的是"给它这个输入,该有这个结果",不是"它内部该这样工作"。好测试让你敢改实现(因为测试守着行为),坏测试让你不敢改(因为一改测试就崩)。
不该用:纯探索/原型(不要求正确,测试是负担);一次性脚本(跑完即弃)。
与相邻 skill 的衔接:testing 在 task-breakdown 下游、verify-and-fix 上游——task 拆出"做完 X 能验证 Y",testing 负责把 Y 写成可重复运行的测试,verify-and-fix 负责跑它验证。三者接力:task 定验证目标 → testing 把目标落地成测试 → verify-and-fix 用测试验证完成。
写测试前先看清"被测的是什么",策略大不相同——这决定了要不要 mock、用什么工具、放哪个层次:
calculateDiscount)→ 直接输入输出断言,零 mock,单元层。识别性质能避免最常见的错配:给纯函数上 mock、给 UI 组件测 state、把单元能测的逻辑推到端到端。先问"它是什么",再问"怎么测"。
这是测试设计的第一原则。测"做什么",不测"怎么做":
calculateDiscount(100, 'vip') 应返回 80。multiply 两次"。为什么测实现糟糕:实现是会变的(重构、换算法、优化),但行为不该变。测实现的测试,每次合理的实现改动都会让它崩——这就是脆弱测试。它逼你改实现时还得改测试,让测试从"保护"变成"负担"。
判别尺子:问自己"如果我把内部实现整个换掉(但行为不变),这个测试还该过吗?" 该过 → 测的是行为(对);崩了 → 测的是实现(错,改)。
例外:有些"交互契约"本身就是行为——比如"调支付时确实发了请求""保存时确实写库了"。这类"验证发生了正确的外部交互"是测行为,不是测实现。区分点:你关心的是结果(钱扣了/数据存了),还是调用细节(调了 3 次不是 2 次)。前者是行为,后者是过度断言。
不是每行代码都值得测。测试有价值,是因为代码有逻辑、可能错。按代码性质分:
判断尺子:这段代码如果写错了,测试能抓住吗?写对了,测试有信息量吗? 两问都否 → 不值得测(如 getter)。把测试预算投到"写错会出事"的地方。
边界和错误路径是重点:happy path 谁都会测,但 bug 大多藏在边界(空值、零、负数、空集合、最大值)和错误路径(异常、超时、依赖失败)。问自己"这个函数在什么输入下会出错?"——那些输入就是要补的测试。
mock 用来隔离外部依赖(数据库、网络、第三方服务、时间),让测试快、稳、可重复。但 mock 容易被滥用:
判断尺子:mock 之后,被测对象的真实逻辑还在被验证吗? 还在(你对 mock 的返回做了真实处理和断言)→ 合理;不在(只是验证"调了 mock")→ 过度,测试失去意义。
mock 的使用原则:
每个测试函数聚焦一个可验证的行为点,断言精简:
testEverything)。discountsVipBy20Percent、returnsOriginalPriceForUnknownLevel)。好名字的价值:测试失败时,名字直接告诉你哪个行为坏了,不用读测试代码。test1 failed 让你去看代码,discountsVipBy20Percent failed 直接定位问题。
测试分三层,数量比例应是金字塔——底层多、顶层少,因为越往上越慢、越脆、越贵:
常见误用:倒金字塔——端到端多、单元少。结果是测试套件又慢又脆,改一处一片红。判断尺子:**这个测试到底在测什么?**测纯逻辑 → 单元;测模块协作 → 集成;测用户能完成目标 → 端到端。能用单元测的别上集成,能用集成的别上端到端。
写测试时常常发现代码行为可疑(如"负价居然照常打折""非数值返回 NaN")。这时别擅自决定——有两种情况:
判别尺子:问"这个行为符合需求/常理吗?" 符合(哪怕反直觉)→ 固化;不符合 → 报告,别固化 bug。把 bug 固化成"通过的测试"是最危险的——它给错误行为盖了"已验证"的章,未来谁想修都会被这个测试挡住。
每个测试用三段结构,清晰可读:
// Arrange:准备输入和依赖
const service = new OrderService(mockDb);
// Act:执行被测行为
const result = await service.create(order);
// Assert:断言结果(行为)
expect(result.id).toBeDefined();
expect(mockDb.save).toHaveBeenCalledWith(order); // 交互契约
三段分离让测试一眼能读懂"测了什么"。混在一起(准备、执行、断言交织)是测试难读、难维护的信号。
| 问题 | 修法 |
|---|---|
| 测实现细节(断言内部调用次数/分支) | 改测行为,问"换实现行为不变,测试还该过吗" |
| mock 掉被测逻辑,退化成测 mock | mock 只隔离外部依赖,被测对象的真实逻辑仍要被验证 |
| 一个测试塞一堆断言 | 一个测试一个行为点,名字描述行为 |
| 测 getter/setter、测框架本身 | 把测试投到有判断的逻辑,跳过无价值的目标 |
| 只测 happy path | 重点补边界(空/零/负/空集合)和错误路径 |
| 追求覆盖率数字而非有效测试 | 覆盖率是必要不充分,从"什么 bug 漏了"反推该测什么 |
| 测试 flaky(时过时不过) | 多半是隐式依赖(时间/随机/顺序/共享状态),排查并隔离 |
| 测试层次倒金字塔(端到端多、单元少) | 金字塔分布:单元最多、集成适量、端到端最少;能下层测的别上上层 |
| 把发现的 bug 固化成"通过的测试" | 先报告确认——是 bug 先修代码再写测试,是预期行为再固化 |