首页/新闻资讯/正文详情

agentic-awesome-skills 测试模式技能解析:Jest/Vitest 工厂函数、Mock 策略与 TDD 红绿重构工作流

发布时间:2026/9/25 15:35:48 来源:云帆数科 栏目:资讯中心
agentic-awesome-skills 测试模式技能解析:Jest/Vitest 工厂函数、Mock 策略与 TDD 红绿重构工作流
AI 技能AI 插件【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,445 agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址https://gitcode.com/gh_mirrors/an/agentic-awesome-skills点击查看免费下载本篇文章以 agentic-awesome-skills 仓库内code-showcase-testing-patterns技能文档位于 SKILL.md为核心系统讲解前端单元测试中的 TDD 工作流、行为驱动测试、工厂函数与 Mock 策略并结合仓库内 Workbench 前端apps/web-app的真实测试源码进行印证与扩展。读完本文你将掌握一套可直接复制到 React Native / React Testing Library 项目中的测试方法论包括自定义 render、组件 props 工厂、数据工厂、模块与 GraphQL Hook 的 Mock 姿势以及测试组织、异步查询与用户交互的推荐写法。技能定位与使用场景code-showcase-testing-patterns是 agentic-awesome-skills 插件库中的社区技能之一其 frontmatter 声明如下namecode-showcase-testing-patternsdescriptionJest testing patterns, factory functions, mocking strategies, and TDD workflow适用于编写单元测试、创建测试工厂、或执行 TDD red-green-refactor 周期riskcritical高风险类技能要求使用前充分验证source_typecommunity源自 ChrisWiles/claude-code-showcaseMIT 许可date_added2026-07-01该技能在仓库中存在两份副本agentic-awesome-skills 插件副本 与 agentic-awesome-skills-claude 插件副本。其适用场景非常聚焦当你需要编写单元测试、为组件/数据创建可复用的测试工厂、或遵循 TDD 的红-绿-重构循环推进功能开发时即可启用此技能。值得注意的是技能示例以 Jest API 书写而当前仓库的 Workbench 前端apps/web-app/package.json实际使用Vitest testing-library/react作为等价实现——scripts中test对应vitest、test:coverage对应vitest run --coveragedevDependencies包含vitest、testing-library/react、testing-library/jest-dom、jsdom。两者 API 高度同构describe/it/expect、jest.fn↔vi.fn、jest.mock↔vi.mock因此文中将同时给出技能原始写法与仓库内的落地形态。测试哲学TDD 与行为驱动测试测试驱动开发TDD技能文档强调的 TDD 流程是先写失败测试 → 写最少代码使其通过 → 变绿后重构并明确要求没有失败测试就不写生产代码。这一原则与本仓库中 tdd 技能 的阐述完全一致TDD 采用**垂直切片vertical slices / tracer bullets**而非水平切片即一个测试 → 一段实现 → 重复切忌先把所有测试一次性写完再一次性实现否则测试会变成对想象中行为的验证而不是对真实行为的验证。行为驱动测试测试行为behavior而不是实现implementation聚焦公共 API 与业务需求避免测试内部实现细节使用能够描述行为的测试名称判断测试是否耦合实现有一个标志重构内部函数导致测试失败、但外部行为并未改变说明该测试测的是实现而非行为。好的测试读起来像一份规格说明书例如用户可以用有效的购物车完成结账。工厂模式Factory Pattern创建getMockX(overrides?: PartialX)形式的工厂函数提供合理的默认值允许覆盖特定属性保持测试 DRY 且易于维护测试工具函数自定义 Render当组件依赖 Context / Provider如主题、国际化、路由时最推荐的做法是写一个自定义 render 函数统一包裹所有必需的 Provider避免每个测试重复嵌套。// src/utils/testUtils.tsx import { render } from testing-library/react-native; import { ThemeProvider } from ./theme; export const renderWithTheme (ui: React.ReactElement) { return render( ThemeProvider{ui}/ThemeProvider ); };用法import { renderWithTheme } from utils/testUtils; import { screen } from testing-library/react-native; it(should render component, () { renderWithTheme(MyComponent /); expect(screen.getByText(Hello)).toBeTruthy(); });仓库中的落地案例可以印证这一模式在 SkillCard.test.tsx 中组件依赖路由上下文测试便通过MemoryRouter包裹后再renderimport { render, screen } from testing-library/react; import { MemoryRouter } from react-router; it(keeps the save control outside the card link, () { render( MemoryRouter SkillCard skill{createMockSkill()} starCount{0} / /MemoryRouter, ); const link screen.getByRole(link, { name: /read skill/i }); const button screen.getByRole(button, { name: /save locally/i }); expect(link).not.toContainElement(button); });工厂模式实战组件 Props 工厂用PartialComponentPropstypeof MyComponent作为覆盖参数类型默认值 展开覆盖符...overrides即可获得类型安全且可定制的 propsimport { ComponentProps } from react; const getMockMyComponentProps ( overrides?: PartialComponentPropstypeof MyComponent ) { return { title: Default Title, count: 0, onPress: jest.fn(), isLoading: false, ...overrides, }; }; // Usage in tests it(should render with custom title, () { const props getMockMyComponentProps({ title: Custom Title }); renderWithTheme(MyComponent {...props} /); expect(screen.getByText(Custom Title)).toBeTruthy(); });数据工厂对接口返回的数据如用户、列表项同样适用interface User { id: string; name: string; email: string; role: admin | user; } const getMockUser (overrides?: PartialUser): User { return { id: 123, name: John Doe, email: johnexample.com, role: user, ...overrides, }; }; // Usage it(should display admin badge for admin users, () { const user getMockUser({ role: admin }); renderWithTheme(UserCard user{user} /); expect(screen.getByText(Admin)).toBeTruthy(); });仓库源码印证真实的 Skill 数据工厂上述模式在仓库 Workbench 前端有完整的生产级实现。位于 apps/web-app/src/factories/skill.ts 的工厂不仅支持单个对象覆盖还扩展出了批量生成与分类生成两个变体import type { Skill } from ../types; /** * Factory function for creating mock skill data */ export function createMockSkill(overrides?: PartialSkill): Skill { return { id: test-skill, name: Test Skill, description: A test skill for testing purposes, category: testing, risk: safe, source: test, date_added: 2024-01-01, path: skills/test/SKILL.md, ...overrides, }; } /** * Factory function for creating an array of mock skills */ export function createMockSkills(count: number): Skill[] { return Array.from({ length: count }, (_, i) createMockSkill({ id: skill-${i}, name: Test Skill ${i}, }) ); } /** * Factory for creating skills with different categories */ export function createMockSkillsByCategory(categories: string[]): Skill[] { return categories.flatMap((category) Array.from({ length: 3 }, (_, i) createMockSkill({ id: ${category}-skill-${i}, name: ${category} Skill ${i}, category, }) ) ); }从中可以提炼出工厂模式的进阶用法基础工厂只承担合理默认值职责复杂的批量/分类场景通过组合基础工厂实现保持每个工厂单一职责。Mocking 策略Mock 整个模块// Mock entire module jest.mock(utils/analytics); // Mock with factory function jest.mock(utils/analytics, () ({ Analytics: { logEvent: jest.fn(), }, })); // Access mock in test const mockLogEvent jest.requireMock(utils/analytics).Analytics.logEvent;Mock GraphQL Hooks对 codegen 生成的 Hook 模块进行整体 mock并在测试内通过mockReturnValue注入不同状态数据 / 加载中 / 错误jest.mock(./GetItems.generated, () ({ useGetItemsQuery: jest.fn(), })); const mockUseGetItemsQuery jest.requireMock( ./GetItems.generated ).useGetItemsQuery as jest.Mock; // In test mockUseGetItemsQuery.mockReturnValue({ data: { items: [] }, loading: false, error: undefined, });仓库源码印证模块 Mock 与全局环境 Stub仓库的测试对上述策略做了更细的落地。例如 SkillCard.test.tsx 用vi.mock替换子组件从而隔离关注点vi.mock(./SkillStarButton, () ({ SkillStarButton: () button typebuttonSave locally/button, }));SelectionFeedback.test.tsx 则展示了更复杂的全局环境 Stub 与副作用断言通过vi.stubGlobal替换URL.createObjectURL / revokeObjectURL用vi.spyOn(HTMLAnchorElement.prototype, click)捕获下载行为并用vi.spyOn(globalThis, fetch)、vi.spyOn(Storage.prototype, setItem)断言不产生网络请求、不写存储const create vi.fn((_value: Blob | MediaSource) blob:feedback-test); const revoke vi.fn((_url: string) {}); vi.stubGlobal(URL, class extends URL { static createObjectURL create; static revokeObjectURL revoke; }); const click vi.spyOn(HTMLAnchorElement.prototype, click).mockImplementation(function (this: HTMLAnchorElement) { expect(this.download).toBe(aas-feedback.json); expect(this.href).toBe(blob:feedback-test); }); const network vi.spyOn(globalThis, fetch); const storage vi.spyOn(Storage.prototype, setItem);这说明一个重要的进阶原则Mock 不只是让代码跑起来更是行为断言的载体——通过 spy 断言副作用下载文件名、URL、是否调用网络/存储是否按预期发生。测试结构组织用嵌套describe将测试按行为维度分组渲染 / 交互 / 边界并在beforeEach中清理 mockdescribe(ComponentName, () { beforeEach(() { jest.clearAllMocks(); }); describe(Rendering, () { it(should render component with default props, () {}); it(should render loading state when loading, () {}); }); describe(User interactions, () { it(should call onPress when button is clicked, async () {}); }); describe(Edge cases, () { it(should handle empty data gracefully, () {}); }); });仓库中的 useSkillShortlist.test.ts 是这一结构在 Hook 测试renderHook上的完整示范并且把边界情况组织得非常有价值空存储、已有存储、损坏的 JSON、混入非字符串条目、浏览器拒绝读存储五种初始化边界全部覆盖import { describe, it, expect, beforeEach, afterEach, vi } from vitest; import { renderHook, act, waitFor } from testing-library/react; import { useSkillShortlist } from ../useSkillShortlist; const STORAGE_KEY aas_skill_shortlist; describe(useSkillShortlist, () { beforeEach(() { localStorage.clear(); vi.clearAllMocks(); }); afterEach(() { vi.restoreAllMocks(); }); describe(Initialization, () { it(starts empty when nothing is stored, () { ... }); it(reads an existing shortlist from localStorage, () { ... }); it(falls back to an empty list for corrupted storage, () { localStorage.setItem(STORAGE_KEY, not-json{); const { result } renderHook(() useSkillShortlist()); expect(result.current.ids).toEqual([]); }); it(drops non-string entries from stored JSON, () { localStorage.setItem(STORAGE_KEY, JSON.stringify([skill-1, 42, null, skill-2])); const { result } renderHook(() useSkillShortlist()); expect(result.current.ids).toEqual([skill-1, skill-2]); }); it(stays usable when the browser rejects storage reads, () { vi.spyOn(Storage.prototype, getItem).mockImplementation(() { throw new DOMException(Storage access denied, SecurityError); }); expect(() renderHook(() useSkillShortlist())).not.toThrow(); }); }); });值得注意的细节beforeEach中vi.clearAllMocks()与afterEach中vi.restoreAllMocks()配合确保 mock 状态在不同测试之间不泄漏——这正是技能文档Clear mocks between tests最佳实践的落地。查询模式Query PatternsTesting Library 的三大查询方法的取舍// Element must exist expect(screen.getByText(Hello)).toBeTruthy(); // Element should not exist expect(screen.queryByText(Goodbye)).toBeNull(); // Element appears asynchronously await waitFor(() { expect(screen.findByText(Loaded)).toBeTruthy(); });getBy*找不到就抛错用于断言元素必须存在queryBy*找不到返回 null用于断言元素不应存在findBy*异步轮询直到出现用于断言异步加载的元素。仓库中大量使用了这一套模式例如 App.workbench-isolation.test.tsx 用screen.findByRole(heading, ...)等待异步渲染、用waitFor(() expect(screen.queryByText(Loading...)).not.toBeInTheDocument())断言加载态消失。用户交互模式User Interaction Patterns通过fireEvent模拟输入与点击然后waitFor断言回调被调用import { fireEvent, screen } from testing-library/react-native; it(should submit form on button click, async () { const onSubmit jest.fn(); renderWithTheme(LoginForm onSubmit{onSubmit} /); fireEvent.changeText(screen.getByLabelText(Email), userexample.com); fireEvent.changeText(screen.getByLabelText(Password), password123); fireEvent.press(screen.getByTestId(login-button)); await waitFor(() { expect(onSubmit).toHaveBeenCalled(); }); });仓库版本web 环境与之几乎一一对应见 SelectionFeedback.test.tsx用fireEvent.click(screen.getByText(Record feedback locally))触发流程、用fireEvent.change(screen.getByLabelText(/Minutes to a useful selection/), { target: { value: 4.5 } })模拟表单输入、用fireEvent.change(screen.getByLabelText(Installation experience), ...)触发依赖联动编辑后使保存按钮消失。反模式必须避免的写法反模式一测试 Mock 行为而非真实行为// Bad - testing the mock expect(mockFetchData).toHaveBeenCalled(); // Good - testing actual behavior expect(screen.getByText(John Doe)).toBeTruthy();判断标准如果断言的是某个 mock 函数被调用了而非其调用的结果对 UI 产生的影响该测试就在测 mock 本身对真实行为毫无保护力。仓库 SelectionFeedback.test.tsx 的写法可作正面参照——它虽然 spy 了click/fetch/storage但核心断言仍是生成的 JSON 内容正确、预览按钮与保存按钮的呈现符合预期这一可观察行为。反模式二不用工厂导致数据重复且不一致// Bad - duplicated, inconsistent test data it(test 1, () { const user { id: 1, name: John, email: johntest.com, role: user }; }); it(test 2, () { const user { id: 2, name: Jane, email: janetest.com }; // Missing role! }); // Good - reusable factory const user getMockUser({ name: Custom Name });手写内联数据有两个问题重复样板代码以及字段遗漏导致的数据不一致上面第二个 test 漏掉了role字段。工厂函数把合法最小数据集收敛到一处测试只表达差异。最佳实践清单始终为 props 和数据使用工厂函数Always use factory functions for props and data测试行为而不是实现Test behavior, not implementation使用描述性的测试名称Use descriptive test names用 describe 块组织测试Organize with describe blocks在测试之间清理 mockClear mocks between tests保持测试聚焦——每个测试只验证一个行为Keep tests focused - one behavior per test运行测试技能文档给出的 Jest 命令# Run all tests npm test # Run with coverage npm run test:coverage # Run specific file npm test ComponentName.test.tsx在仓库的 apps/web-app/package.json 中等价命令是 Vitest 形态test: vitest, test:coverage: vitest run --coverage因此实际执行cd apps/web-app # 运行全部测试监听模式 npm test # 单次运行并统计覆盖率 npm run test:coverage # 只运行指定测试文件 npx vitest run src/hooks/__tests__/useSkillShortlist.test.ts覆盖率的支持来自devDependencies中的vitest/coverage-v8测试环境由jsdom提供。另外注意仓库的engines要求 Node^22.22.2 || ^24.15.0 || 26.0.0运行测试前请先确认本机 Node 版本满足要求。与其他技能的协同react-ui-patterns配套测试 UI 的全部分支状态——loading、error、empty、success仓库中 react-ui-patterns 技能systematic-debugging在修复 bug 之前先写一个能复现该 bug 的测试对应仓库 systematic-debugging 技能的思路让测试成为调试过程的回归防线。使用限制与注意事项技能文档自身的Limitations部分明确提醒仅在任务与上游来源及本地项目上下文明确匹配时使用本技能在应用改动之前务必验证命令、生成的代码、依赖、凭据与外部服务行为不要将示例当作环境特定测试、安全审查或用户授权的替代品——涉及破坏性、昂贵或生产环境的操作必须先获得用户批准。结合其risk: critical属性本技能在启用时应当被当作方法论参考而非自动执行指令所有生成代码都应经过本地真实环境的验证例如先运行npm test确认测试真实通过再继续推进。小结code-showcase-testing-patterns技能本质上是一套前端单元测试工程规范以 TDD 红-绿-重构为流程主线、以行为驱动测试为断言哲学、以工厂函数与 Mock 策略为可复用基建并以自定义 render、查询模式与交互模式作为 Testing Library 的具体手法。本文结合仓库 Workbench 前端的真实测试factories/skill.ts、SkillCard.test.tsx、useSkillShortlist.test.ts、SelectionFeedback.test.tsx展示了这些模式在生产代码库中的落地形态——从文档里的模式到仓库里的实现两者互相印证可直接作为你下一个组件或 Hook 编写测试时的参照模板。赞分享AI 技能AI 插件【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,445 agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址https://gitcode.com/gh_mirrors/an/agentic-awesome-skills点击查看免费下载相关推荐Superpowers 的 TDD 技能解析红-绿-重构循环与先看测试失败的 Agent 测试纪律Superpowers 的 TDD 技能解析红 绿 重构循环与先看测试失败的 Agent 测试纪律 Superpowers 是一个面向编码 Agent 的AI 技能AI 插件开发工具RuView SPARC 实现专家 Agent 模板解析TDD 红绿重构工作流与 Claude Code Agent 定义实战RuView SPARC 实现专家 Agent 模板解析TDD 红绿重构工作流与 Claude Code Agent 定义实战 本篇基于 RuView 仓库中人工智能计算机视觉物联网智能家居后端嵌入式awesome-copilot 测试自动化插件指南从 TDD 红绿重构到 Playwright 端到端测试awesome copilot 测试自动化插件指南从 TDD 红绿重构到 Playwright 端到端测试 本指南基于 awesome copilot htt文档知识库AI 技能/插件上一篇WandEnhancer 上手笔记10 分钟把 WeMod 的高级功能装进本地下一篇Sunshine 游戏串流服务 Docker 部署全攻略一条命令让 Moonlight 串流稳定跑起来创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

OpenChamber 新特性前瞻:Session Timeline 时间线视图、扩展浏览器代理与全类型文件预览
OpenChamber 新特性前瞻:Session Timeline 时间线视图、扩展浏览器代理与全类型文件预览

AI Agent人工智能代码智能体交互助手 【免费下载链接】openchamber Agentic Development Environment based on OpenCode AI agent 项目地址: https://gitcode.com/gh_mirrors/op/openchamber 点击查看 免费下载 本文基于仓库中 changelog/unreleased.md 记录的下一… · 2026/9/25 15:35:22

Atlas 300V部署YOLO全流程:从环境配置到性能实测与踩坑记录
Atlas 300V部署YOLO全流程:从环境配置到性能实测与踩坑记录

前阵子一位做安防项目的朋友,拿着块 Atalas 300V 24G 的卡过来问我:这玩意儿是不是运算加速卡?我说是,但你得先搞清楚,它加速的是“推理”,不是“训练”。后来他又问,现有这套 YOLO 检测模型能不… · 2026/9/25 15:35:10

国产麒麟系统安装部署OpenClaw完整指南(适配V10/VSP)国产操作系统的AI智能体部署
国产麒麟系统安装部署OpenClaw完整指南(适配V10/VSP)国产操作系统的AI智能体部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 15:35:10

AI时代FDE前线部署工程师:从需求勘探到交付的实战方法论
AI时代FDE前线部署工程师:从需求勘探到交付的实战方法论

1. 从"实现不再是瓶颈"说起:FDE 到底在解决什么问题这两年跟不少做研发的朋友聊天,大家有个共同的感受:写代码这件事本身,正在变得越来越不"值钱"。不是说代码不重要,而是说"把需求翻译成能跑… · 2026/9/25 15:56:36

Atlas 300V 24G推理卡部署YOLO:从ONNX到OM全流程与调优实践
Atlas 300V 24G推理卡部署YOLO:从ONNX到OM全流程与调优实践

最近在技术群里连续被问了好几次同一个问题:“Atlas 300V 24G 是运算加速卡吗?”紧接着下一句通常是:“我想用它部署 YOLO,能不能直接当显卡用?”老实说,这两个问题放在一起,恰好是很多刚接触昇… · 2026/9/25 15:56:36

Atlas 300V 24G部署YOLO:AI推理加速卡环境搭建与模型转换实战
Atlas 300V 24G部署YOLO:AI推理加速卡环境搭建与模型转换实战

很多人第一次拿到Atlas 300V 24G的时候,都会有一个很朴素的疑问:这东西到底是不是运算加速卡?答案很明确,是一块实打实的AI推理加速卡。但它和我们平时听说的游戏显卡、通用GPU不是一回事,如果你指望拿它去渲染画面&am… · 2026/9/25 15:56:36

SpringBoot整合MQTT实现软硬件通信实战
SpringBoot整合MQTT实现软硬件通信实战

1. 项目概述:为什么软硬件通信必须跨过“协议鸿沟”在工业现场、智能楼宇、农业物联网这些真实场景里,我见过太多团队卡在同一个地方:后端服务写得再漂亮,前端页面再炫酷,一到要跟温湿度传感器、PLC控制器、电表采集器… · 2026/9/25 15:56:17

Atlas 300V 24G实战:从PyTorch到昇腾的YOLO模型迁移与部署
Atlas 300V 24G实战:从PyTorch到昇腾的YOLO模型迁移与部署

1. 一张加速卡,为什么值得单独写一篇先说结论:Atlas 300V 24G 确实是运算加速卡,而且还是目前边缘端推理部署里相当能打的一类硬件。这两年 AI 项目落地时,很多团队在 GPU 和国产加速卡之间反复纠结,我自己的实测感受是… · 2026/9/25 15:56:05

Atlas 300V实战:基于昇腾AI加速卡的YOLO推理部署全攻略
Atlas 300V实战:基于昇腾AI加速卡的YOLO推理部署全攻略

1. Atlas 300V到底是什么先说结论:Atlas 300V Pro(也就是大家常说的Atlas 300V 24G)确实是一块运算加速卡,但它不是普通意义上的“显卡”。它是一块专门为AI推理设计的加速卡,主要任务是把已经训练好的深度学习模型&am… · 2026/9/25 15:56:05

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码