用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/peel/fiddle --skill tdd命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | tdd |
| description | Use when implementing any feature or bugfix, before writing implementation code |
Write the test first, watch it fail, then write the minimal code that makes it pass.
The test is written and seen failing before the implementation exists. A test never seen red proves nothing: it may exercise the wrong path, assert on the implementation instead of the behavior, or pass for a reason unrelated to the feature, and you have no way to tell which. Watching it fail is the only evidence that it tests something.
New features, bug fixes, refactoring, and behavior changes all go through the cycle. Throwaway prototypes, generated code, and configuration files are the standing exceptions, and taking one is a decision to raise with your human partner rather than make alone.
If production code was written before its test, delete it and implement fresh from the tests. Keeping it as reference and adapting it while writing the tests is testing after with extra steps. Deleting hours of work feels wasteful, but that time is spent either way; what remains is a choice between code you can trust and code you cannot.
Write one minimal test showing what should happen: one behavior, a name describing that behavior, real code rather than mocks unless mocking is unavoidable.
Good:
test('retries failed operations 3 times', async () => {
let attempts = 0;
const operation = () => {
attempts++;
if (attempts < 3) throw new Error('fail');
return 'success';
};
const result = await retryOperation(operation);
expect(result).toBe('success');
expect(attempts).toBe(3);
});
Bad (vague name, and it asserts on the mock rather than on the code under test):
test('retry works', async () => {
const mock = jest.fn()
.mockRejectedValueOnce(new Error())
.mockRejectedValueOnce(new Error())
.mockResolvedValueOnce('success');
await retryOperation(mock);
expect(mock).toHaveBeenCalledTimes(3);
});
npm test path/to/test.test.ts
Confirm the test fails rather than errors, that the failure message is the one you expected, and that it fails because the feature is missing rather than because of a typo.
If it passes, it is testing behavior that already exists, so fix the test. If it errors, fix the error and re-run until it fails correctly.
Write the simplest code that passes the test. No extra features, no refactoring of neighboring code, no improvements beyond what the test demands.
Good (just enough to pass):
async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
for (let i = 0; i < 3; i++) {
try {
return await fn();
} catch (e) {
if (i === 2) throw e;
}
}
throw new Error('unreachable');
}
Bad (options nothing asked for):
async function retryOperation<T>(
fn: () => Promise<T>,
options?: {
maxRetries?: number;
backoff?: 'linear' | 'exponential';
onRetry?: (attempt: number) => void;
}
): Promise<T> {
// YAGNI
}
npm test path/to/test.test.ts
Confirm the test passes, the other tests still pass, and the output is pristine, with no errors and no warnings. If the new test fails, fix the code, not the test. If other tests fail, fix them now.
Only after green: remove duplication, improve names, extract helpers. Tests stay green and behavior stays unchanged.
Then write the next failing test for the next behavior.
| Quality | Good | Bad |
|---|---|---|
| Minimal | One thing. "and" in name? Split it. | test('validates email and domain and whitespace') |
| Clear | Name describes behavior | test('test1') |
| Shows intent | Demonstrates desired API | Obscures what code should do |
Tests written before the code force edge cases into the open while the design is still movable; tests written after only confirm the cases you happened to remember, and they inherit the implementation's blind spots.
| 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. |
Found a bug? Write a failing test reproducing it, then run the cycle. The test proves the fix and prevents the regression, which is why bug fixes are not exempt from the ordering above.
When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls: