principle-test-behavior-not-implementation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTest Behavior, Not Implementation
测试行为,而非实现
A test calls the code the way its users do and asserts the result they observe against a literal expected value. A test that asserts which calls the code made, or restates a constant the code contains, does neither.
The check: before you keep a test, ask whether it would still pass if every function it imports returned . If yes, it observes no behavior and cannot fail for a defect. Rewrite the assertion or delete the test.
undefinedWhy: A test that cannot fail for a defect costs CI time and review attention and catches nothing. A constant pin also fails when someone edits the constant or the prompt it restates, so it prevents that edit.
Five shapes that still pass when every imported function returns :
undefined- Weak or no assertion. No , or only
expect,toBeDefined,toBeTruthy,not.toThrow,toBeInstanceOf.toBeGreaterThan(0) - Mock or absence only. Only ,
toHaveBeenCalled,not.toHaveBeenCalled,toBeUndefined,toEqual([]),toHaveLength(0).not.toBe(wrongValue) - Self-referential. The expected value comes from the code under test: ,
expect(f(a)).toBe(f(a)).expect(parsed.url).toBe(buildUrl(...)) - Constant pin. The assertion restates a hand-maintained constant, config default, table row, or prompt string: ,
expect(LIMITS.maxTools).toBe(8).expect(PROMPT).toContain("You are") - Fixture asserts fixture. The assertion reads data the test built or a value computed in , and the subject never runs inside the body.
beforeEach
The fix: call the subject inside the test body with one concrete input and assert the literal output or the observable effect, . For an absence, assert the presence on the other input in the same test. For a constant, test the mechanism that reads it with one input instead of restating the value. For a mock, assert the payload it received or the state after the call, not that it was called. When no such assertion exists, delete the test.
expect(slugify("Hello, World!")).toBe("hello-world")Keep a test of a relation across a table's rows (a key present in two tables, a parent that exists), and a compile-time check in a file.
*.test-d.ts测试应像用户一样调用代码,并将观察到的结果与字面量预期值进行断言。断言代码进行了哪些调用,或只是重述代码中包含的常量的测试,两者都做不到这一点。
检查方法:在保留测试前,问问自己:如果测试导入的每个函数都返回 ,该测试是否仍会通过?如果是,它就没有观察到任何行为,也无法因缺陷而失败。请重写断言或删除该测试。
undefined原因: 无法因缺陷而失败的测试会消耗 CI 时间和评审注意力,却什么也捕获不到。固定常量的断言还会在有人编辑该常量或其重述的提示词时失败,因此会阻碍这类编辑。
以下五种形式在所有导入函数都返回 时仍会通过:
undefined- 断言薄弱或不存在。 没有 ,或者只使用
expect、toBeDefined、toBeTruthy、not.toThrow、toBeInstanceOf。toBeGreaterThan(0) - 仅验证 Mock 或不存在状态。 只使用 、
toHaveBeenCalled、not.toHaveBeenCalled、toBeUndefined、toEqual([])、toHaveLength(0)。not.toBe(wrongValue) - 自引用。 预期值来自被测代码:、
expect(f(a)).toBe(f(a))。expect(parsed.url).toBe(buildUrl(...)) - 固定常量的断言。 断言重述了手动维护的常量、配置默认值、表格行或提示词字符串:、
expect(LIMITS.maxTools).toBe(8)。expect(PROMPT).toContain("You are") - Fixture 断言 Fixture。 断言读取的是测试自身构建的数据,或 中计算出的值,且被测对象在测试体内从未运行。
beforeEach
修复方法: 在测试体内用一个具体输入调用被测对象,并断言字面量输出或可观察效果,例如 。如果要验证某项不存在,请在同一个测试中用另一个输入断言其存在。对于常量,应使用一个输入测试读取该常量的机制,而不是重述其值。对于 Mock,应断言其接收到的载荷或调用后的状态,而不是断言它是否被调用。如果不存在这样的断言,请删除该测试。
expect(slugify("Hello, World!")).toBe("hello-world")保留 跨表格各行关系的测试(例如,一个键存在于两个表中、某个父项存在),以及 文件中的编译时检查。
*.test-d.ts