用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill tdd命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | tdd |
| description | Use when implementing any feature or bugfix, before writing implementation code |
| metadata | {"author":"aboio-labs"} |
Write the test first. Watch it fail. Write minimal code to pass.
Core principle: If you didn't watch the test fail, you don't know if it tests the right thing.
Violating the letter of the rules is violating the spirit of the rules.
Follow references/token-efficiency.md rules. When finding test files or understanding code to test, use Grep and targeted reads instead of reading entire source files.
Always:
Exceptions (ask your human partner):
Thinking "skip TDD just this once"? Stop. That's rationalization.
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
Write code before the test? Delete it. Start over.
No exceptions:
Implement fresh from tests. Period.
digraph tdd_cycle {
rankdir=LR;
red [label="RED\nWrite failing test", shape=box, style=filled, fillcolor="#ffcccc"];
verify_red [label="Verify fails\ncorrectly", shape=diamond];
green [label="GREEN\nMinimal code", shape=box, style=filled, fillcolor="#ccffcc"];
verify_green [label="Verify passes\nAll green", shape=diamond];
refactor [label="REFACTOR\nClean up", shape=box, style=filled, fillcolor="#ccccff"];
next [label="Next", shape=ellipse];
red -> verify_red;
verify_red -> green [label="yes"];
verify_red -> red [label="wrong\nfailure"];
green -> verify_green;
verify_green -> refactor [label="yes"];
verify_green -> green [label="no"];
refactor -> verify_green [label="stay\ngreen"];
verify_green -> next;
next -> red;
}
Write one minimal test showing what should happen.
```gleam import gleeunit/should import myapp/retrypub fn retries_failed_operations_3_times_test() { let operation = fn(state) { let attempts = state + 1 case attempts < 3 { True -> Error(#(attempts, "fail")) False -> Ok(#(attempts, "success")) } }
retry.retry_operation(operation, 0) |> should.be_ok |> should.equal(#(3, "success")) }
Clear name, tests real behavior, one thing
</Good>
<Bad>
```gleam
pub fn retry_works_test() {
// Vague name
retry.retry_operation(some_mock_fn, 0)
|> should.be_ok
}
Vague name, doesn't show what behavior is tested
Requirements:
MANDATORY. Never skip.
gleam test
Confirm:
Test passes? You're testing existing behavior. Fix test.
Test errors? Fix error, re-run until it fails correctly.
Write simplest code to pass the test.
```gleam pub fn retry_operation( operation: fn(a) -> Result(#(a, b), #(a, String)), initial_state: a, ) -> Result(#(a, b), #(a, String)) { do_retry(operation, initial_state, 0) }fn doretry( operation: fn(a) -> Result(#(a, b), #(a, String)), state: a, attempt: Int, ) -> Result(#(a, b), #(a, String)) { case operation(state) { Ok(result) -> Ok(result) Error(#(new_state,)) if attempt < 2 -> do_retry(operation, new_state, attempt + 1) Error(e) -> Error(e) } }
Just enough to pass
</Good>
<Bad>
```gleam
pub fn retry_operation(
operation: fn(a) -> Result(#(a, b), #(a, String)),
initial_state: a,
options: RetryOptions, // YAGNI
) -> Result(#(a, b), #(a, String)) {
// Configurable max retries, backoff strategies, callbacks...
// Over-engineered
}
Over-engineered
Don't add features, refactor other code, or "improve" beyond the test.
MANDATORY.
gleam test
Confirm:
Test fails? Fix code, not test.
Other tests fail? Fix now.
After green only:
Keep tests green. Don't add behavior.
Next failing test for next feature.
| Quality | Good | Bad |
|---|---|---|
| Minimal | One thing. "and" in name? Split it. | pub fn validates_email_and_domain_and_whitespace() |
| Clear | Name describes behavior | pub fn test1_test() |
| Shows intent | Demonstrates desired API | Obscures what code should do |
"I'll write tests after to verify it works"
Tests written after code pass immediately. Passing immediately proves nothing:
Test-first forces you to see the test fail, proving it actually tests something.
"I already manually tested all the edge cases"
Manual testing is ad-hoc. You think you tested everything but:
Automated tests are systematic. They run the same way every time.
"Deleting X hours of work is wasteful"
Sunk cost fallacy. The time is already gone. Your choice now:
The "waste" is keeping code you can't trust. Working code without real tests is technical debt.
"TDD is dogmatic, being pragmatic means adapting"
TDD IS pragmatic:
"Pragmatic" shortcuts = debugging in production = slower.
"Tests after achieve the same goals - it's spirit not ritual"
No. Tests-after answer "What does this do?" Tests-first answer "What should this do?"
Tests-after are biased by your implementation. You test what you built, not what's required. You verify remembered edge cases, not discovered ones.
Tests-first force edge case discovery before implementing. Tests-after verify you remembered everything (you didn't).
30 minutes of tests after ≠ TDD. You get coverage, lose proof tests work.
| Excuse | Reality |
|---|---|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. |
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
| "Manual test faster" | Manual doesn't prove edge cases. You'll re-test every change. |
| "Existing code has no tests" | You're improving it. Add tests for existing code. |
All of these mean: Delete code. Start over with TDD.
Bug: Empty email accepted
RED
import gleeunit/should
import myapp/form
pub fn rejects_empty_email_test() {
form.submit_form(FormData(email: ""))
|> should.be_error
}
Verify RED
$ gleam test
FAIL: Expected Error, got Ok(...)
GREEN
pub type FormData {
FormData(email: String)
}
pub fn submit_form(data: FormData) -> Result(Nil, String) {
case string.trim(data.email) {
"" -> Error("Email required")
_ -> Ok(Nil)
}
}
Verify GREEN
$ gleam test
PASS
REFACTOR Extract validation for multiple fields if needed.
Before marking work complete:
Can't check all boxes? You skipped TDD. Start over.
| Problem | Solution |
|---|---|
| Don't know how to test | Write wished-for API. Write assertion first. Ask your human partner. |
| Test too complicated | Design too complicated. Simplify interface. |
| Must mock everything | Code too coupled. Use dependency injection. |
| Test setup huge | Extract helpers. Still complex? Simplify design. |
Bug found? Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression.
Never fix bugs without a test.
When adding mocks or test utilities, read testing-anti-patterns.md to avoid common pitfalls:
When running TDD in a Lustre frontend codebase (client app, components), also load /gleam:frontend-testing. It enforces behavioral-only tests (model, update, interactions, ARIA) and documents simulate limitations. Without it, tests tend to drift into CSS class assertions that break on every visual refresh.
For compile-time languages like Gleam where you can't call non-existent functions, read compile-time-language-testing.md to learn how to write RED tests that compile but fail due to missing behavior:
To prove test-first discipline and create verifiable TDD workflow, read red-green-commit-structure.md for the commit pattern:
This pattern creates an audit trail proving tests were written before implementation.
Production code → test exists and failed first
Otherwise → not TDD
No exceptions without your human partner's permission.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.