在编写或修改测试时识别反模式,避免错误 mock 与污染生产代码。
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "testing-anti-patterns" 技能: 1. 下载 https://raw.githubusercontent.com/microsoft/FluidFramework/main/.agency/plugins/nori/skills/testing-anti-patterns/SKILL.md 2. 保存为 ~/.claude/skills/testing-anti-patterns/SKILL.md 3. 装好后重载技能,告诉我可以用了
请检查这组单元测试改动,找出测试反模式:是否在测试 mock 的行为、是否为了测试给生产代码新增了仅测试用方法、是否在不了解依赖关系时过度 mock,并给出更合理的重构建议。
指出具体测试反模式、风险说明,以及更贴近真实行为的测试重构建议。
我准备给这个测试添加多个 mock。请先分析被测对象的真实依赖关系,判断哪些依赖应该保留、哪些适合替身,并说明如何避免把测试写成只验证 mock 交互的形式。
一份依赖分析与 mock 使用建议,帮助减少不必要的替身并提升测试有效性。
我想为了方便测试在生产代码里加一个仅测试使用的方法。请评估这是不是反模式,并提供不修改对外接口或不引入测试专用方法的替代测试方案。
说明这样做的问题,并给出通过重构结构、依赖注入或更高层测试来替代的方案。
Tests must verify real behavior, not mock behavior. Mocks are a means to isolate, not the thing being tested.
Core principle: Test what the code does, not what the mocks do.
Following strict TDD prevents these anti-patterns.
1. NEVER test mock behavior
2. NEVER add test-only methods to production classes
3. NEVER mock without understanding dependencies
The violation:
// ❌ BAD: Testing that the mock exists
test('renders sidebar', () => {
render(<Page />);
expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument();
});
Why this is wrong:
your human partner's correction: "Are we testing the behavior of a mock?"
The fix:
// ✅ GOOD: Test real component or don't mock it
test('renders sidebar', () => {
render(<Page />); // Don't mock sidebar
expect(screen.getByRole('navigation')).toBeInTheDocument();
});
// OR if sidebar must be mocked for isolation:
// Don't assert on the mock - test Page's behavior with sidebar present
BEFORE asserting on any mock element:
Ask: "Am I testing real component behavior or just mock existence?"
IF testing mock existence:
STOP - Delete the assertion or unmock the component
Test real behavior instead
The violation:
// ❌ BAD: destroy() only used in tests
class Session {
async destroy() {
// Looks like production API!
await this._workspaceManager?.destroyWorkspace(this.id);
// ... cleanup
}
}
// In tests
afterEach(() => session.destroy());
Why this is wrong:
The fix:
// ✅ GOOD: Test utilities handle test cleanup
// Session has no destroy() - it's stateless in production
// In test-utils/
export async function cleanupSession(session: Session) {
const workspace = session.getWorkspaceInfo();
if (workspace) {
await workspaceManager.destroyWorkspace(workspace.id);
}
}
// In tests
afterEach(() => cleanupSession(session));
BEFORE adding any method to production class:
Ask: "Is this only used by tests?"
IF yes:
STOP - Don't add it
Put it in test utilities instead
Ask: "Does this class own this resource's lifecycle?"
IF no:
STOP - Wrong class for this method
The violation:
// ❌ BAD: Mock breaks test logic
test('detects duplicate server', () => {
// Mock prevents config write that test depends on!
vi.mock('ToolCatalog', () => ({
discoverAndCacheTools: vi.fn().mockResolvedValue(undefined),
}));
await addServer(config);
await addServer(config); // Should throw - but won't!
});
Why this is wrong:
The fix:
// ✅ GOOD: Mock at correct level
test('detects duplicate server', () => {
// Mock the slow part, preserve behavior test needs
vi.mock('MCPServerManager'); // Just mock slow server startup
await addServer(config); // Config written
await addServer(config); // Duplicate detected ✓
});
BEFORE mocking any method:
STOP - Don't mock yet
1. Ask: "What side effects does the real method have?"
2. Ask: "Does this test depend on any of those side effects?"
3. Ask: "Do I fully understand what this test needs?"
IF depends on side effects:
…
将长期复杂任务拆分为可执行小步骤,减少上下文超限与遗漏
通过结构化追问与方案比较,把模糊想法梳理成可执行设计。
帮助你严谨评估代码评审意见,澄清疑点后再决定是否采纳与实现
用四阶段系统化排查框架定位缺陷根因,再制定可靠修复方案。
帮助团队识别客户可见 API 变更并判断发布、评审与弃用流程要求
帮助你实现与迭代界面和交互体验,完成前端集成与设计优化。
帮助开发者编写关注行为、抗重构且可验证修复意图的高质量测试。
通过先写失败测试再实现代码,帮助稳定完成功能开发与缺陷修复。
沉淀并查询代码库经验教训,帮助开发、验证与评审减少重复踩坑。
帮助开发者用 MockDeviceKit 无需实体眼镜即可进行应用测试与调试。
帮助你为复杂问题编写调试测试并反复验证,快速定位异常根因。
快速搭建一次性原型,验证方案可行性并给出对比结论。