技能使用指南

testing(TypeScript测试文件规范)Skill 是什么?

TypeScript测试文件规范Skill(testing)为 *.test.ts 提供文件头文档模板、行为断言命名、测试拆分策略、setup() 工厂模式与 @ts-expect-error 类型测试约定,帮你把测试写得好读好维护。本文讲清技能功能、安装验证步骤、使用流程、竞品对比与典型场景,附高频FAQ,开发者与团队负责人可快速上手落地。

TypeScript测试文件规范Skilltesting
8 个章节 约 17 分钟阅读 AI 智能生成

TypeScript测试文件规范Skill:让每一份 *.test.ts 都自带说明书

  • 它是什么:一套面向 *.test.ts 文件的「测试写作约定」技能,覆盖文件级文档注释、测试命名、拆分策略、setup() 工厂模式、负面类型测试等具体规则。
  • 解决什么问题:测试文件越写越乱、命名含糊(“应该正确工作”)、beforeEach 藏状态、满屏 as any 绕过类型检查,Review 时无人能说清这个文件到底在验证什么。
  • 怎么用:在编写或修改 *.test.ts、创建测试设置函数、评审测试结构时调用,让 AI 按约定生成结构与命名,而不是自由发挥。
  • 核心收益:把「测试评审靠资深同学口头传授」变成「可复制的书面约定」,新人第一次写测试就能输出团队级质量。
  • 适配场景:TypeScript 库开发、CRDT/同步逻辑测试、公共 API 类型约束验证、团队测试规范统一。

该技能叫什么?如何下载安装 AI 技能提升开发效率?

技能中文名:TypeScript测试文件规范Skill 技能英文名:testing 技能ID:11856

这个技能要解决的问题非常具体:TypeScript 项目里,测试代码往往是最缺规范的一环。生产代码有 lint、有类型检查、有代码评审清单,但 .test.ts 文件经常是「能跑就行」——文件名随便起、beforeEach 里塞一堆可变状态、失败时报错信息是「应该正确工作」,排查问题时等于没说。该技能的技能详情把这类问题拆成了可落地的一条条约定:文件开头必须有 JSDoc 说明「测什么、关键行为有哪些」,测试名必须是行为断言,共享基础设施必须走 setup() 工厂函数,类型约束必须用 @ts-expect-error 验证而不是 as any 绕过。

一键安装的思路:AI 技能本质上是把一份结构化的领域知识挂到你的 AI 编码助手上,让它在生成或评审测试代码时「先查规矩再动手」。整体流程是三步:

  1. 确认安装前提:你使用的 AI 编码工具支持加载 AI 技能(Skill)或自定义规则文件;项目本身是 TypeScript 项目,且已确定测试框架(技能内容以 bun:test 为背景说明,若你使用其他框架,需要按官方说明做适配)。
  2. 通过技能入口安装:在所用工具的技能市场 / 技能管理面板中搜索技能 ID 11856 或英文名 testing 完成安装;若工具支持手动导入,也可将技能内容导入为自定义规则。具体命令、入口位置与是否需要登录,以官方说明为准。
  3. 验证是否生效:新建或打开一个 *.test.ts 文件,让助手「按测试文件约定为某模块补一个测试文件」。如果它输出的文件以一个解释「测什么 + 关键行为」的 JSDoc 块开头、测试名是行为断言、共享状态通过 setup() 返回对象,说明技能已生效;如果只是普通地堆几个 test(),则需检查技能是否被正确启用。

这种「一键安装」的价值在于:你不需要先读完一份几千字的技术规范,也不需要把它翻译成团队内部的 Wiki——装好之后,规范会在你真正写下第一行测试代码时自动出现。

该技能的主要功能和特点

  • 文件级文档注释模板:强制每个 .test.ts 以 JSDoc 块开头,包含模块名、1–3 句说明、关键行为 列表和 另见 相关文件指引。它相当于把「这个测试文件的合同」写在最上面,技能里还专门给了「太简略」的反例(一行 // 测试 create-tables)作为警示。
  • 多维度测试文件拆分策略:明确规定 {模块}.test.ts 放核心 CRUD 与快乐路径、{模块}.types.test.ts 放类型推断验证、{模块}.{场景}.test.ts 放特定场景(如 CRDT 同步、离线、集成);同时给出「何时拆」(超过约 500 行、关注点真正不同)和「何时不拆」(拆完不足 3 个测试、所有测试共享同一套设置)的边界。
  • 行为断言式测试命名:测试名必须是「发生了什么」,而不是「应该正确工作」。技能提供了 {动作} {结果} [条件] 的结构化模式,并用逐字对齐的示例说明如何拆解,还列出「应该」「正确」「适当」这类填充词属于反模式。
  • 负面类型测试规范:用 @ts-expect-error — [原因] 验证编译器确实拒绝了错误类型,要求每条断言只配一个 @ts-expect-error,并统一收拢到 describe('类型错误', ...) 块中。
  • as any 的替代方案表:把「测试里图省事用 as any」按场景给出替代做法(走公共 API、构造正确类型的 mock、暴露仅测试访问器),并明确只有测试「无效输入的运行时错误处理」时才允许保留,且必须写注释说明原因。
  • setup() 工厂模式:要求设置函数总是返回对象(即使只有一个值),测试总是解构取值,setup() 是普通函数而非钩子,每个测试独立调用以获得全新状态;还给出「可组合设置变体」(如 setupWithBinding)的写法。
  • 禁止用 beforeEach 做数据设置:beforeEach / afterEach 只保留给「即使测试失败也必须运行」的清理工作(关服务器、恢复 spy),避免隐式可变状态。
  • 模块级共享无状态定义:schema 与表定义放在模块级共享,有状态实例(如 Y.Doc、工作空间实例)放进 setup()。
  • 不返回死重:setup() 返回的每个字段都应至少被一个测试使用,杜绝「为了看起来完整」而无用返回。
  • 扁平优于嵌套 + 长文件分节:优先扁平 test(),describe() 只用于区分真正不同的行为类别;超过 100 行的长文件用 // ==== 注释标题分节。

和普通工具比强在哪:ESLint 这类工具能告诉你「这里语法不合规」,但很难告诉你「这个测试名没有信息量」「这个文件该拆成三个」。该技能补的正是「结构与语义层面」的约定,而且给出的是带正反例的模板,可直接照抄。

如何使用该技能?

以下步骤以「在 AI 编码助手中调用该技能」为典型路径,具体触发方式以你所用工具的官方说明为准。

第 1 步:触发技能 在编写或修改 *.test.ts、创建测试设置函数、或评审测试结构时调用。可以是一句自然语言指令,例如:

按测试文件约定,为「消息同步模块」新建一个测试文件。

第 2 步:把上下文交代清楚 技能能落地的关键,是你告诉它三件事:被测模块名、要验证的关键行为、是否涉及类型约束。示例输入:

模块:message-sync;关键行为:① 对相同字段的并发编辑取最新时间戳 ② 对不同字段的并发编辑两者保留 ③ 删除移除行的所有单元;另外需要一份类型测试,验证 upsert 缺少必填字段时编译报错。

第 3 步:让它先产出文件头 JSDoc 按约定,输出应形如:

/**
 * 消息同步测试
 *
 * 验证消息同步模块的冲突合并行为,确保并发编辑不会互相覆盖。
 *
 * 关键行为:
 * - 相同字段并发编辑:最新时间戳获胜
 * - 不同字段并发编辑:两者保留(合并)
 * - 删除移除行的所有单元
 *
 * 另见:
 * - `message-sync.types.test.ts` 用于类型约束验证
 */

第 4 步:判断是否需要拆分文件 对照约定:如果同时存在 CRUD、同步、类型三类关注点,且文件预计超过约 500 行,就拆成 message-sync.test.ts、message-sync.types.test.ts;如果拆完某文件不足 3 个测试,则合并回去。

第 5 步:编写 setup() 要求返回对象并被解构使用:

function setup() {
	const ydoc = new Y.Doc();
	const ykv = new YKeyValueLww(ydoc.getArray('test-table'));
	return { ydoc, ykv };
}

test('存储行后可按 key 检索', () => {
	const { ykv } = setup();
	ykv.set('1', { name: 'Alice' });
	expect(ykv.get('1')).toEqual({ name: 'Alice' });
});

第 6 步:按行为断言命名测试 把「应该正确工作」改写成「upsert 存储行且 get 检索它」「get() 对不存在的表抛出带提示的错误」这类能直接说明「哪里坏了」的句子。

第 7 步:补负面类型测试(如适用) 在 describe('类型错误', ...) 中逐条写 @ts-expect-error,每条断言只配一个,并写明原因。

第 8 步:交付前自查 检查清单:文件头有 JSDoc 吗?测试名是行为断言吗?有没有 as any 而无注释?beforeEach 是否只用于清理?setup() 返回值是否都有测试在用?结构是否过度嵌套?

同类型竞品对比分析

方案名称 定位 核心功能 安装/使用门槛 适用场景 优势与不足
TypeScript测试文件规范Skill(testing) 测试结构与约定的「知识型」技能 文件头文档模板、拆分策略、命名规则、setup() 工厂、负面类型测试、as any 替代表 需在支持技能的 AI 工具中安装,零配置即可获得约定建议 新写测试、重构测试结构、测试代码评审 优势:覆盖语义与结构约定,带正反例,可直接落地;不足:不替代 linter,无法自动拦截语法级问题,需人主动调用
ESLint + typescript-eslint 规则集 静态代码检查工具 语法与规则检查、格式约束、部分反模式告警 需配置规则、维护配置文件,团队要统一版本 CI 卡口、格式化统一 优势:自动化、强制性强;不足:难以表达「测试名是否有信息量」「文件该怎么拆」这类语义判断,自定义规则开发成本高
团队 Wiki 规范文档 + Code Review 清单 人工约定 书面规范、评审 checklist 零技术门槛,但需要人写、人读、人记 团队制度化管理 优势:灵活、可定制;不足:沉淀成本高、执行靠自觉,新人上手慢,规范容易过期
通用 AI 编码助手(无技能) 通用代码生成 按上下文补全测试代码 开箱即用 快速写「能跑」的测试 优势:零准备;不足:默认风格自由发挥,常出现模糊测试名、as any、beforeEach 堆状态
tsd / expect-type 等类型测试工具 类型断言专用库 类型层面的断言与 CI 校验 需引入依赖并编写类型测试文件 公共 API 类型约束验证 优势:类型测试能力强;不足:只管类型,不管测试组织、命名与设置结构

一句话选型建议:要「自动化卡口」用 ESLint 类工具,要「结构与写法指导 + 生成期对齐约定」用本技能,两者互补而非替代。

该技能的典型应用场景与实际体验情况

场景一:CRDT / 同步逻辑的测试作者 痛点:并发合并类测试最怕「测了个寂寞」——名字写着「测试同步」,失败时完全看不出是哪个行为坏了。使用方式:让技能先产出文件头 JSDoc 列出三条关键行为,再把每条行为写成独立测试,命名直接用「对不同字段的并发编辑:两者保留」这种带条件的断言句。实际体验:文件从头到尾读一遍就知道覆盖了什么,Review 效率明显提升;注意点是关键行为要在动手写之前列清楚,写完再补 JSDoc 容易变成事后描述。

场景二:开源库/内部库的维护者写类型测试 痛点:公共 API 的类型约束经常没测,「传入错误字段」这种问题只能靠用户踩坑反馈。使用方式:单独建 {模块}.types.test.ts,把 @ts-expect-error 断言收进 describe('类型错误'),并说明每个断言期望什么错误。实际体验:类型回归在 tsc --noEmit 阶段就被拦住;注意点是一条断言只配一个 @ts-expect-error,堆叠会让报错定位困难,另外技能内容基于 bun:test 场景(无 expectTypeOf),若你使用其他框架需按官方说明调整写法。

场景三:技术负责人做测试结构评审 痛点:评审时看到 800 行的 xxx.test.ts,说不清该不该拆。使用方式:让技能对照「超过约 500 行」「关注点是否真正不同」「拆完是否不足 3 个测试」三条边界给出建议,并顺手检查 setup() 是否返回了没人用的死重。实际体验:评审意见从「感觉有点乱」变成「建议拆成 CRUD 与同步两个文件」,讨论成本明显下降。

场景四:新人第一次给项目写测试 痛点:不知道该建什么文件、函数怎么组织,只好照抄隔壁文件,把 beforeEach 的可变状态一并抄了过来。使用方式:直接让助手「按测试文件约定写这个模块的测试」。实际体验:上手难度低,产出结构接近团队既有风格;注意点是要提醒助手模块级 schema 共享、有状态实例放 setup(),否则容易出现共享单例导致测试互相污染。

该技能能为用户带来的价值

  • 把隐性经验变成显性约定:文件头文档、命名规则、拆分边界、setup() 模式都以「规则 + 正例 + 反例」的形式固化,不再依赖某位资深同学的口头传授。
  • 显著压缩沟通成本:测试失败时的报错名从「应该正确工作」变成「删除与更新竞争:更新获胜(最右条目)」,定位问题的时间从「翻代码猜」变成「读名字就知道」。
  • 降低类型安全的风险:通过 @ts-expect-error 正面验证类型约束、明确禁止无注释的 as any,把「测试里绕过类型检查」这条隐性技术债堵在源头。
  • 提升可维护性,减少回归成本:工厂式 setup() + 禁止数据型 beforeEach,让每个测试拿到全新状态,避免测试间相互污染造成的偶发失败。
  • 长期价值:一套稳定的测试结构约定,是项目从「几个人写」走向「多人协作、长期维护」时最划算的基础设施投资——它不产生新功能,但决定了未来每次改动要付出多少验证成本。

常见问题 FAQ

Q1:这个技能怎么安装?需要付费吗? A:在支持 AI 技能的编码工具中,通过技能市场或技能管理入口搜索技能 ID 11856 或英文名 testing 安装即可;是否支持手动导入、具体命令与入口位置,以官方说明为准。至于收费情况,同样需以官方说明为准,本技能内容本身是一份测试约定文档,不涉及额外的运行依赖。

Q2:它和 ESLint 冲突吗?装了是不是就不需要 lint 了? A:不冲突,也不替代。ESLint 负责「语法与规则级」的自动卡口,本技能负责「结构与语义级」的写法指导——比如测试名是否有信息量、文件该不该拆分、setup() 该不该返回对象。实践中推荐两者并用:lint 管机器能判的,技能管机器难判的。

Q3:我的项目不用 bun:test,还能用吗? A:技能的绝大部分约定(文件头注释、命名、拆分、setup() 工厂、禁止数据型 beforeEach、as any 替代)与测试框架无关。只有类型测试部分明确以 bun:test 为背景(无 expectTypeOf,靠 tsc --noEmit 兜底),若你使用其他框架,可按官方说明与所选框架的类型测试能力做适配。

Q4:适合谁用?只写业务代码的同学需要吗? A:适合所有会写或评审 *.test.ts 的人——尤其是 TypeScript 库作者、需要维护公共 API 类型约束的开发者、以及负责测试规范落地的技术负责人。只写业务页面的同学同样受益:它能把「测试写得能看懂」这件事的门槛降到「照着模板填」。

Q5:和直接用通用 AI 助手写测试有什么区别? A:通用助手倾向于产出「能跑」的测试,风格随上下文漂移,常见模糊命名、as any、beforeEach 堆状态;本技能在生成前先约束结构与命名,产出更接近团队已有的高质量测试文件。如果你的项目对测试结构没有要求,通用助手就够了;如果你在意长期可维护性,技能带来的差异会在半年后的回归排查中体现出来。