spa单元测试规范核心是统一入口、隔离上下文、复用工具链、分层断言;通过test/setup.js集中配置、测试文件与src结构镜像、工厂函数创建独立状态、封装高阶断言,实现稳定可维护的测试体系。

在单页应用(SPA)中组织全局单元测试规范,核心是统一测试入口、隔离测试上下文、复用测试工具链、按模块分层断言。不追求“全覆盖”,而要确保关键逻辑可预测、可回溯、可协作。
统一测试启动与配置入口
避免每个模块各自 require 测试框架或重复配置。在项目根目录下设 test/setup.js(或 test/bootstrap.js),集中处理:
- 自动加载 Jest/Vitest 全局 mock(如
fetch、localStorage、路由对象) - 注入 SPA 共享依赖(如 Pinia store 工厂、Vue app 实例模板、React Query client)
- 设置默认超时、清理钩子(
afterEach(() => cleanup()))、覆盖率阈值 - 启用模块路径别名解析(如
@/composables→src/composables),让测试代码路径与源码一致
按功能域划分测试文件结构
测试目录结构应镜像 src,而非按“test/unit”扁平堆砌。例如:
src/
├── stores/
│ ├── user.ts
│ └── user.test.ts ← 模块内联测试,专注 store 逻辑
├── composables/
│ ├── useAuth.ts
│ └── useAuth.test.ts
├── router/
│ └── routes.ts ← 路由守卫、权限规则等纯逻辑抽离至此
└── utils/
└── apiClient.ts ← 封装 fetch 的纯函数,便于 mock
这样开发者修改 useAuth.ts 时,自然会看到并更新同级的 .test.ts,提升维护意识。
全局状态与副作用需显式隔离
SPA 中的全局状态(如路由、store、主题、i18n)容易导致测试污染。推荐做法:
- 每个测试文件顶部调用
vi.resetModules()(Vitest)或jest.resetModules(),防止模块缓存干扰 - 使用工厂函数创建独立 store 实例:
const store = createPinia(); const userStore = useUserStore(store) - 路由测试不依赖真实 history,而是传入 mock 的
router对象(如{ currentRoute: { value: { path: '/home' } } }) - 对
localStorage等浏览器 API,统一在setup.js中 mock,禁止在单个 test 文件里重复覆盖
定义可复用的测试断言契约
针对 SPA 常见模式,提炼高阶断言工具,减少样板代码:
-
expectAsync(fn).resolves.toBeDefined()封装为shouldResolve(fn),用于异步 action 测试 - 为路由守卫写
assertGuardAllows(to, from, options)和assertGuardBlocks(to, from, options) - 对组合式函数,约定输入输出类型检查:
expect(result.count.value).toBe(0); expect(typeof result.increment).toBe('function') - 组件测试中,避免深查 DOM,优先断言暴露的 props、emits、返回值;用
screen.queryByRole替代document.querySelector
不复杂但容易忽略:测试不是越“全”越好,而是越“稳”越好——稳定复现、稳定通过、稳定反馈问题。从 setup 入口统一、到模块就近存放、再到状态隔离和契约断言,四步落地,就能让 SPA 的单元测试真正成为开发节奏的一部分。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











