mcpField
T
tdd

tdd

github.com/help-me-test测试与质量036 次安装4 周前更新
代码仓库

关于 tdd

面向 helpmetest 的测试驱动开发与测试维护 Skill,指导编码 Agent 先规划场景、编写测试并验证,再分析故障。它还要求在测试操作前后向用户说明进展。

主要功能

  1. 01先写测试的功能与修复流程
  2. 02任务和功能制品规划
  3. 03场景覆盖优先级排序
  4. 04交互式测试探索与验证
  5. 05失败分类与修复指引
  6. 06测试操作前后说明进展

适用场景

  1. 01以测试优先启动功能或重构
  2. 02为现有功能补充测试
  3. 03诊断并修复失败测试

MCP 相关

该 Skill 指导 Agent 使用 helpmetest MCP 工具检查状态、搜索制品、交互运行和验证测试;MCP 不可用时可改用 `helpmetest `。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/help-me-test/skills --skill tdd

安装后在 Claude Code 中输入/tdd确认已加载。

附带文件references/examples/wishlist-example.md

详细介绍

你是谁: 如果 .helpmetest/SOUL.md 存在,请阅读它——它定义了你的角色。

没有 MCP? 使用 helpmetest <command>,而不是 MCP 工具。


🔴 先写测试。

修改代码 → 运行测试。 新功能 → 先写测试,再写代码。 测试就是规范。测试通过,工作才算完成。 没有测试 = 尚未完成。


讲述你的操作

创建测试、生成制品或运行测试时,绝不能保持沉默。 始终告诉用户:

  • 之前: 你准备做什么以及为什么(覆盖什么场景、防范什么风险)
  • 之后: 发生了什么——结果、制品包含什么、测试为何失败
  • 接下来: 你将做什么,以及即将遇到的决策点

沉默意味着用户完全不知道你做了什么,也不知道原因。

测试——编写、生成、修复

先了解情况(始终如此)

在做任何事情之前,检查现有内容:

helpmetest_status()
helpmetest_search_artifacts({ query: "" })
helpmetest_search_artifacts({ type: "Tasks" })
  • 测试已经失败?→ 这是优先事项,而不是创建新测试
  • 任务制品正在进行中?→ 恢复处理,不要从头开始
  • 功能制品已存在?→ 使用它们,不要重新探索

使用场景

“我需要构建一些东西”(TDD)

新功能、Bug 修复或重构。先写测试——它们定义了“完成”的含义。

1. 创建任务制品以跟踪工作:

{
  "id": "tasks-[feature-name]",
  "type": "Tasks",
  "content": {
    "overview": "What this implements and why",
    "tasks": [
      { "id": "1.0", "title": "Write all tests first", "status": "pending", "priority": "critical" },
      { "id": "2.0", "title": "Implement to make tests pass", "status": "pending" },
      { "id": "3.0", "title": "All green — review for gaps", "status": "pending" }
    ]
  }
}

2. 创建功能制品,在编写任何测试之前列出所有场景:

{
  "id": "feature-[name]",
  "type": "Feature",
  "content": {
    "goal": "What this feature does",
    "functional": [
      { "name": "User can do X", "given": "...", "when": "...", "then": "...", "tags": ["priority:critical"], "test_ids": [] }
    ],
    "edge_cases": [],
    "bugs": []
  }
}

3. 在编写任何测试之前规划覆盖范围。 对于每项功能,按以下四种类型列出场景:

类型始终?要问的问题
关键路径✅ 始终一切正常时,真实用户会怎么做?
错误路径✅ 始终在生产环境中,最可能出现的 3 种故障方式是什么?
边界条件涉及数据/逻辑时行为会在哪个阈值处发生变化?
边缘情况有选择地QA 工程师会测试哪些开发人员不会测试的情况?

为每个场景标记:立即编写(高/关键优先级)/ 发布前编写(中优先级)/ 跳过(仅外观问题、已有覆盖或结果不可靠)。不要测试所有内容——测试出问题会造成损失的内容。

4. 编写所有测试——正常路径、边缘情况、错误路径——然后再开始实现。失败的测试就是你的规范。

5. 逐步实现——选择优先级最高的失败测试,让它通过,再继续下一个。

6. 完成条件: 所有测试均通过,并且你已检查是否遗漏边缘情况。


“为现有功能编写测试”

功能已经存在(或刚由其他人实现)。你的工作仅限于编写测试。

1. 阅读功能制品 — helpmetest_get_artifact({ id: "feature-X" })。如果不存在,请先根据你掌握的信息创建一个。

2. 编写测试前先进行交互式探索 — 使用 helpmetest_run_interactive_command 逐步运行场景。观察真实行为后编写的测试会使用真实选择器,并反映实际时序。根据描述编写测试只是在猜测。

As  <persona>
Go To  <url>
# Execute each Given/When/Then step, observe what actually happens

3. 编写每个测试前,先大声回答:

“如果这个测试通过了,但功能实际上有问题,那么在客户报告之前,我们会漏掉用户的什么投诉?”

将答案写为 [Documentation] 中的 PROTECTS: 行。这是测试对用户作出的承诺——不是可有可无的套话。如果无法用一句话回答,说明场景还需要进一步思考,而不是编写测试。

**4. 按 priority:critical、high、medium 的顺序优先编写测试。对于每个测试:

  • 至少包含 5 个有意义的步骤
  • 验证业务结果(数据已保存、状态已更改),而不只是元素可见
  • 对任何注册/电子邮件字段,使用 Create Fake Email——绝不硬编码
  • [Documentation] 必须以 PROTECTS: <此测试捕获的用户投诉> 开头

5. 验证每个测试:在将其关联到场景之前,先使用 fix-tests 进行验证。如果功能损坏时测试仍能通过,就必须重写——只有验证器返回 PASS,测试才算完成。

6. 关联测试 — 只有在验证通过后,才将每个测试 ID 添加到功能制品中的 scenario.test_ids。

7. 运行并修复 — 如果新编写的测试失败,请参阅下方的“修复损坏的测试”。


“修复损坏的测试”/“测试失败”

首先:了解失败模式

检查近期代码更改:

git diff --stat HEAD
git log --oneline -5

将已更改的文件映射到可能的原因:

  • components/、pages/ → 选择器更改
  • auth/、session/ → 身份验证状态问题
  • api/、routes/ → 后端错误或响应结构发生变化

然后获取测试历史记录:helpmetest_status({ id: "test-id", testRunLimit: 10 })

分类:

  • 代码更改后持续失败 → 选择器/行为发生变化
  • PASS/FAIL 交替出现且错误不断变化 → 隔离问题(共享状态、测试顺序依赖)
  • 超时/元素不可见 → 时序问题
  • 身份验证/会话错误 → 状态未正确恢复
  • 测试输出中出现后端错误 → 真实缺陷,而非测试问题

交互式复现——修复前务必执行

逐个运行失败的步骤:

As  <persona>
Go To  <url>
# Execute each step, observe what actually happens at the point of failure

对于“找不到元素”:列出该类型的所有元素,并尝试其他选择器。 对于“值错误”:检查实际显示的内容与测试预期的内容。 对于超时:尝试延长等待时间,并检查元素是否会出现。

判断:是测试问题还是应用程序缺陷?

  • 测试问题(选择器发生变化、时序问题、预期错误)→ 修复测试,并在保存前通过交互式方式验证修复
  • 应用程序缺陷(功能确实损坏)→ 在 feature.bugs[] 中记录,并将 Feature.status 更新为 "broken" 或 "partial"

UI 更改后许多测试都失败了?

按顺序逐个处理。对于每个测试:

  1. 对失败进行分类(通常是选择器或时序问题)
  2. 交互式复现
  3. 修复
  4. 运行以确认

不要靠猜测进行大范围修复——一次错误的修复会导致两个测试损坏。

重构后测试已过时?

  1. 获取测试列表:helpmetest_status()
  2. 对于每个失败的测试,检查功能制品中的场景是否仍符合预期行为
  3. 如果代码是事实依据 → 更新测试
  4. 如果测试没有问题,而重构破坏了行为 → 记录回归问题

编写测试

结构
As  <persona>          # auth state — always first
Go To  <url>

# Given — establish precondition
<steps>

# When — perform the action
<steps>

# Then — verify the outcome
<assertions>

# Persistence check (if relevant)
Reload
<re-assert that state survived>
文档格式

每个测试都必须在 [Documentation] 中包含四行明确说明:

[Documentation]
...    Given: <precondition — what state the system is in before the action>
...    When: <action — what the user/system does>
...    Then: <outcome — what is asserted, specifically>
...    Risk: <what silent failure this catches — user complaint if this test were deleted>

完整示例:

[Documentation]
...    Given: registered user with valid account
...    When: submits login form with wrong password
...    Then: sees "Invalid email or password" error, remains on login page, is NOT authenticated
...    Risk: silent login failure — attacker gets in, or user is confused with no feedback

Given/When/Then——优质描述的特点:

  • ✅ Given: registered user with valid account — 明确的前置条件
  • ✅ When: submits login form with wrong password — 确切的操作
  • ✅ Then: sees "Invalid email or password" error, remains on login page, is NOT authenticated — 具体列出多项断言
  • ❌ Given: user is logged in | When: they do something | Then: it works — 内容模糊,测试失败时毫无参考价值

语言规则——描述必须让产品经理也能读懂:

  • ✅ 使用用户操作和可见结果来描述
  • ❌ 绝不写 CSS 选择器、XPath 或 DOM 类名(.keyword-line.current、#submit-btn、div[data-id])
  • ❌ 绝不写 JavaScript 内部细节、变量名或调试 API(replayDebug.currentKeyword、window.__state)
  • ❌ 绝不写 Robot Framework 语法、关键字名称或技术实现细节
  • 选择器应写在测试主体中。描述应面向产品经理。

错误:

Given: replay loaded with .banner-keywords visible
When: user clicks .banner-next and replayDebug.currentKeyword changes
Then: .keyword-line.current text matches window.replayDebug.currentKeyword.split(/ {2,}/)[0]

正确:

Given: a test replay is open and paused
When: user steps forward then backward through keywords using the navigation buttons
Then: the highlighted keyword in the banner matches the current playback position after each navigation

Risk——优质示例:

  • ✅ Risk: users completing checkout get charged without receiving an order confirmation
  • ✅ Risk: users typing wrong passwords are silently logged in or shown a blank screen
  • ✅ Risk: profile email changes silently fail — user sees stale email with no indication
  • ❌ Risk: the login form breaks — 太模糊了,具体哪里出问题?谁会注意到?
  • ❌ Risk: the form doesn't submit — 这描述的是测试要做什么,而不是测试要防范什么
行内注释

每个不明显的步骤上方都必须添加一条面向产品经理、而非工程师的 # comment。

注释应说明某个步骤为何存在、用户正在经历什么,或测试在检查什么——而不是说明关键字的作用。

# User opens an existing test replay — this is the entry point for debugging failed tests
Go To  https://helpmetest.example.com/test/some-test

# The banner shows the current keyword being replayed — it must stay in sync with what's actually executing
Click  css=.banner-next

# After stepping forward, the highlighted keyword in the banner must change to match the new position
# If this fails, users see the wrong keyword highlighted while debugging — they investigate the wrong step
${label}=  Get Text  css=.keyword-line.current .keyword-text
Should Contain  ${label}  ${expected_keyword}

以下情况必须添加注释:

  • 任何 Javascript 调用——说明它读取或更改了什么用户可见的状态
  • 任何 Hover 或 Sleep——说明界面为何需要这一步(悬停以显示隐藏元素,等待动画完成)
  • 任何多步骤断言组——说明这组断言共同验证了什么
  • 任何不属于明显页面导航的设置步骤
优质测试的特点

✅ 验证业务结果——数据已保存、筛选器已应用、订单已创建 ✅ 如果功能损坏,测试就会失败 ✅ 包含 5 个或更多有意义的步骤 ✅ 检查状态是否发生变化,而不只是检查按钮是否存在

❌ 只导航到页面并统计元素数量 ❌ 点击某个元素,却不检查发生了什么 ❌ 功能损坏时测试仍然通过

测试命名

格式:User can <action> 或 <Feature> <behavior>

  • ✅ User can update profile email
  • ✅ Cart total updates when quantity changes
  • ❌ MyApp Login Test
  • ❌ SiteName Checkout
身份验证

使用一次 Save As <StateName> 来保存身份验证状态。在每个测试中使用 As <StateName> 复用该状态——绝不要在测试中重新进行身份验证。

电子邮件

使用 Create Fake Email——绝不要硬编码 [email protected]。硬编码的电子邮件地址会在第二次运行时失效。

${email}=  Create Fake Email
Fill Text  input[name=email]  ${email}
${code}=   Get Email Verification Code  ${email}
本地主机

如果要测试本地服务,请先设置代理:

helpmetest_proxy({ action: "start", domain: "dev.local", sourcePort: 3000 })

编写任何测试之前,先确认代理可正常工作。详情请参阅 proxy 技能。


标签

  • priority:critical|high|medium|low
  • feature:[feature-name]
  • type:e2e|smoke|regression

完成标准

  • ✅ 所有测试均已通过
  • ✅ 所有 priority:critical 场景都有 test_ids
  • ✅ 每个测试的 [Documentation] 中都有 Given:、When:、Then:、Risk: 行
  • ✅ 每个测试在关联之前都已通过 /fix-tests
  • ✅ Bug 已记录在 feature.bugs[] 中
  • ✅ 已更新 Feature.status(working / broken / partial)
  • ✅ Tasks 工件全部完成

最终摘要格式

结尾绝不要写“创建了 N 个测试,其中 M 个通过”。请使用以下格式:

## What you can now trust works
- <user-facing statement> (test: <id>)
- <user-facing statement> (test: <id>)

## What's still unprotected
- <what could silently break with no test catching it>

## Bugs found
- <bug description> — documented in feature.bugs[]

如果第一部分无法用面向用户的语言来写,你的测试就还没有完成。

评论

支持 Markdown