17 KiB
17 KiB
测试指南
**本文引用的文件** - [fms-vue/vitest.config.js](file://fms-vue/vitest.config.js) - [fms-vue/package.json](file://fms-vue/package.json) - [fms-vue/tests/setup.js](file://fms-vue/tests/setup.js) - [fms-vue/tests/helpers/app.js](file://fms-vue/tests/helpers/app.js) - [fms-vue/tests/components/input.spec.js](file://fms-vue/tests/components/input.spec.js) - [fms-vue/tests/services/http.spec.js](file://fms-vue/tests/services/http.spec.js) - [fms-vue/tests/views/login.spec.js](file://fms-vue/tests/views/login.spec.js) - [fms-api/pom.xml](file://fms-api/pom.xml) - [fms-api/src/test/java/cn/g3soft/fmsapi/FmsApiApplicationTests.java](file://fms-api/src/test/java/cn/g3soft/fmsapi/FmsApiApplicationTests.java) - [fms-api/src/test/java/cn/g3soft/fmsapi/service/AuthServiceTests.java](file://fms-api/src/test/java/cn/g3soft/fmsapi/service/AuthServiceTests.java)目录
简介
本指南面向 FMS 项目的测试实践,覆盖前后端测试策略、框架选择、用例编写规范、Mock 策略、覆盖率与报告生成、以及常见场景的示例与最佳实践。前端采用 Vitest + Vue Test Utils + jsdom;后端采用 Spring Boot Test(Jupiter)+ Mockito。文档同时给出端到端(E2E)建议与落地方式,帮助团队在 CI 中稳定运行并持续改进质量。
项目结构
FMS 为前后端分离工程:
- 前端 fms-vue:使用 Vite 构建,Vitest 执行单元测试与组件测试,jsdom 提供浏览器环境模拟,Vue Test Utils 挂载/浅渲染组件,Pinia 状态管理,Vue Router 路由。
- 后端 fms-api:Spring Boot 应用,使用 spring-boot-starter-webmvc-test 进行控制器/服务层测试,JUnit Jupiter 作为测试引擎,Mockito 打桩外部依赖。
graph TB
subgraph "前端 fms-vue"
A["Vitest 配置<br/>vitest.config.js"]
B["测试入口与命令<br/>package.json scripts"]
C["全局环境初始化<br/>tests/setup.js"]
D["测试辅助工具<br/>tests/helpers/app.js"]
E["组件/页面/服务测试<br/>tests/*/*.spec.js"]
end
subgraph "后端 fms-api"
F["Maven 依赖与测试启动器<br/>pom.xml"]
G["应用上下文测试<br/>FmsApiApplicationTests.java"]
H["服务层测试<br/>AuthServiceTests.java"]
end
A --> E
B --> E
C --> E
D --> E
F --> G
F --> H
图表来源
- fms-vue/vitest.config.js:1-34
- fms-vue/package.json:1-48
- fms-vue/tests/setup.js:1-57
- fms-vue/tests/helpers/app.js:1-71
- fms-api/pom.xml:1-108
- fms-api/src/test/java/cn/g3soft/fmsapi/FmsApiApplicationTests.java:1-14
- fms-api/src/test/java/cn/g3soft/fmsapi/service/AuthServiceTests.java:1-72
章节来源
核心组件
- 前端测试基础设施
- Vitest 配置:启用 jsdom 环境、全局变量、setupFiles、关闭 CSS、v8 覆盖率与阈值。
- 全局初始化:mock nprogress、polyfill ResizeObserver/IntersectionObserver/matchMedia/scrollTo 等浏览器 API。
- 测试助手:createTestPinia(带 persist)、createTestRouter(memory history)、mountPage(shallowMount + 插件注入)。
- 后端测试基础设施
- Maven 依赖:spring-boot-starter-webmvc-test 提供 @WebMvcTest/@SpringBootTest 能力。
- 应用上下文测试:@SpringBootTest 验证应用可加载。
- 服务层测试:通过 Mockito mock 外部依赖,反射注入被测对象字段,断言业务逻辑。
章节来源
- fms-vue/vitest.config.js:12-31
- fms-vue/tests/setup.js:1-57
- fms-vue/tests/helpers/app.js:17-71
- fms-api/pom.xml:86-96
- fms-api/src/test/java/cn/g3soft/fmsapi/FmsApiApplicationTests.java:1-14
- fms-api/src/test/java/cn/g3soft/fmsapi/service/AuthServiceTests.java:18-42
架构总览
前后端测试分层与协作关系如下:
- 前端
- 单元/组件测试:Vitest + jsdom + Vue Test Utils,聚焦组件行为、事件、状态变化。
- 服务层测试:mock 统一请求模块,验证拦截器与错误处理。
- 页面集成测试:mountPage 装配 Pinia/Router,验证路由跳转与会话写入。
- 后端
- 单元测试:Mockito 隔离数据库/JWT 等外部依赖,验证服务方法。
- 集成测试:@SpringBootTest 启动容器,验证装配与上下文。
- Web 层测试:基于 webmvc-test 的控制器断言(可按需扩展)。
sequenceDiagram
participant Dev as "开发者"
participant FE as "前端测试(Vitest)"
participant BE as "后端测试(Spring Boot)"
participant DB as "数据库(可选)"
participant Ext as "外部依赖(Mock)"
Dev->>FE : 运行 pnpm test / test : coverage
FE->>FE : setup.js 初始化环境
FE->>FE : helpers/app.js 装配 Pinia/Router
FE->>Ext : vi.mock 请求/消息等
FE-->>Dev : 组件/页面/服务用例结果
Dev->>BE : 运行 mvn test
BE->>BE : @SpringBootTest 启动上下文
BE->>Ext : Mockito 打桩 DbUtils/JwtUtils
BE-->>DB : 按需连接(或跳过)
BE-->>Dev : 服务/控制器用例结果
图表来源
- fms-vue/tests/setup.js:1-57
- fms-vue/tests/helpers/app.js:17-71
- fms-api/pom.xml:86-96
- fms-api/src/test/java/cn/g3soft/fmsapi/service/AuthServiceTests.java:18-42
详细组件分析
前端测试环境与工具链
- 环境初始化
- 全局 polyfill:ResizeObserver、IntersectionObserver、matchMedia、Element.scrollTo/scrollIntoView,避免 jsdom 缺失导致的异常。
- 第三方库 Mock:nprogress 的全局方法被替换为空实现,避免 DOM 副作用。
- 测试助手
- createTestPinia:创建带 persist 插件的 Pinia 实例并安装,保证 store 行为与生产一致。
- createTestRouter:内存历史路由,支持初始 location。
- mountPage:浅渲染组件,自动注入 Pinia/Router,便于页面级测试。
flowchart TD
Start(["测试启动"]) --> Setup["执行 tests/setup.js"]
Setup --> Polyfills["注入浏览器 API polyfill"]
Polyfills --> Helpers["导入 helpers/app.js"]
Helpers --> Pinia["createTestPinia() 安装 persist"]
Pinia --> Router["createTestRouter(memory history)"]
Router --> Mount["mountPage(shallowMount)"]
Mount --> RunSpecs["执行 *.spec.js 用例"]
图表来源
章节来源
组件测试示例:输入框 Input
- 目标:验证默认/密码/数字/文本域模式下的渲染、事件转发、状态切换、边界行为。
- 要点:
- 使用 data-slot/aria-label 定位元素,不依赖样式类名。
- 异步更新使用 nextTick/flushPromises,避免固定延时。
- 对复杂交互(拖拽调整高度)使用原生事件触发并断言最终状态。
sequenceDiagram
participant T as "测试用例"
participant M as "Input 组件"
participant I as "原生 input/textarea"
T->>M : mount(Input, props)
T->>I : setValue('...')
I-->>M : 触发 update : modelValue/change
M-->>T : 断言事件/属性/类名
图表来源
章节来源
页面集成测试示例:登录页
- 目标:验证登录流程中的会话写入、路由跳转、持久化存储清理。
- 要点:
- 使用 mountPage 装配 Pinia/Router,mock 统一 API 层。
- beforeEach 清理 localStorage/sessionStorage,防止跨用例污染。
- 使用 flushPromises + nextTick 等待异步完成。
sequenceDiagram
participant U as "用户操作"
participant P as "登录页组件"
participant S as "auth store"
participant R as "router"
U->>P : 提交表单
P->>S : setSession(token,user,org)
S-->>P : 状态更新(isAuthenticated=true)
P->>R : push(redirect)
R-->>U : 跳转到目标页
图表来源
章节来源
服务层测试示例:HTTP 拦截器
- 目标:验证请求头注入 Authorization、响应码处理(成功/401/业务错误/网络异常)。
- 要点:
- 仅 mock 统一请求模块,确保确定性驱动。
- 断言是否注入 token、跳转路径、抛错信息。
flowchart TD
Req["发起请求"] --> CheckToken{"存在 token?"}
CheckToken --> |是| AddAuth["注入 Authorization"]
CheckToken --> |否| SkipAuth["不注入"]
AddAuth --> Send["发送请求"]
SkipAuth --> Send
Send --> Resp{"响应 code"}
Resp --> |0| Success["返回成功数据"]
Resp --> |401| ClearLogin["清会话并跳转 /login?reason=expired"]
Resp --> |40101| ClearReplace["清会话并跳转 /login?reason=session-replaced"]
Resp --> |其他| ThrowErr["抛出业务错误"]
图表来源
章节来源
后端服务层测试示例:认证服务
- 目标:验证登录逻辑,包括隐藏超级管理员空密码登录、JWT 生成、用户信息组装。
- 要点:
- 使用 Mockito mock DbUtils/JwtUtils,反射注入到被测对象。
- 断言返回值包含 token、user 字段正确性。
sequenceDiagram
participant T as "测试用例"
participant A as "AuthService"
participant DB as "DbUtils(Mock)"
participant JWT as "JwtUtils(Mock)"
T->>A : login(org, account, password, ...)
A->>DB : loadUserForAuthentication(...)
DB-->>A : 用户数据
A->>JWT : generateToken(account, org, secret)
JWT-->>A : token
A-->>T : Optional<Map> {token, user}
图表来源
章节来源
端到端(E2E)测试建议
- 技术选型:Playwright(推荐)或 Cypress。Playwright 在多浏览器、并行、录制调试方面优势明显。
- 场景建议:
- 登录 -> 进入仪表盘 -> 打开模块管理 -> 新增/编辑/删除 -> 退出登录。
- 权限控制:不同角色访问受限页面应重定向或提示。
- 与现有脚本:仓库中存在 .playwright-cli 目录,可作为参考脚本组织方式。
[本节为概念性说明,不直接分析具体源码文件]
依赖关系分析
- 前端
- Vitest 依赖 jsdom 提供 DOM 环境;Vue Test Utils 用于组件挂载;Pinia 与 Router 通过 helpers 注入。
- 覆盖率由 @vitest/coverage-v8 提供,输出 text/html 报告。
- 后端
- spring-boot-starter-webmvc-test 提供测试能力;JUnit Jupiter 为测试引擎;Mockito 用于依赖打桩。
graph LR
V["Vitest"] --> JSDOM["jsdom"]
V --> VTU["@vue/test-utils"]
VTU --> PINIA["Pinia"]
VTU --> ROUTER["Vue Router"]
V --> COV["@vitest/coverage-v8"]
SB["Spring Boot Test"] --> JUnit["JUnit Jupiter"]
SB --> Mockito["Mockito"]
图表来源
章节来源
性能考虑
- 前端
- 使用 shallowMount 减少子组件渲染开销,仅在需要时 mount。
- 避免真实网络请求,集中 mock 统一 API 层。
- 合理使用 nextTick/flushPromises,避免 setTimeout 猜测时序。
- 后端
- 单元测试尽量无数据库依赖,使用 Mockito 隔离外部系统。
- 集成测试按需启用数据库,必要时使用内存库或测试专用配置。
- 控制测试数据规模,避免大数据量导致用例缓慢。
[本节为通用指导,不直接分析具体源码文件]
故障排查指南
- 前端常见问题
- jsdom 未实现的 API 报错:检查 tests/setup.js 是否已 polyfill。
- Pinia persist 不生效:确保使用 createTestPinia,而非直接 setActivePinia(createPinia())。
- 跨用例状态泄漏:beforeEach 清理 localStorage/sessionStorage。
- 异步断言失败:使用 flushPromises + nextTick,避免固定延时。
- 后端常见问题
- 上下文加载失败:检查 @SpringBootTest 配置与依赖注入。
- 外部依赖未 mock:确认 DbUtils/JwtUtils 等已被 mock 并设置期望。
- 反射注入失败:确保字段名与类型匹配。
章节来源
- fms-vue/tests/setup.js:1-57
- fms-vue/tests/helpers/app.js:17-31
- fms-api/src/test/java/cn/g3soft/fmsapi/service/AuthServiceTests.java:18-42
结论
本项目已形成清晰的前后端测试体系:前端以 Vitest 为核心,配合 jsdom 与 Vue Test Utils,建立稳定的组件/页面/服务层测试;后端以 Spring Boot Test 为基础,结合 JUnit 与 Mockito,保障服务逻辑正确性。通过统一的覆盖率门槛与报告机制,可在 CI 中持续把控质量。建议逐步补齐关键路径的 E2E 测试,进一步提升交付信心。
[本节为总结性内容,不直接分析具体源码文件]
附录
测试命令速查
- 前端
- 全部测试:pnpm test
- 单文件测试:pnpm test:file tests/views/login.spec.js
- 覆盖率:pnpm test:coverage
- 监听模式:pnpm test:watch
- 后端
- 全部测试:mvn test
- 指定类:mvn test -Dtest=FmsApiApplicationTests
- 指定包:mvn test -Dtest="cn.g3soft.fmsapi.service.*"
章节来源
覆盖率要求与报告
- 前端
- 覆盖率提供者:v8
- 报告格式:text、html
- 统计范围:src/**/*.{js,vue}
- 排除项:src/main.js、src/theme/presets.js
- 阈值:lines/functions/branches/statements ≥ 60%
- 后端
- 可使用 JaCoCo 集成(如需),在 pom.xml 中配置 maven-surefire-plugin 与 jacoco-maven-plugin 生成报告。
章节来源
测试数据管理
- 前端
- 使用本地 fixture 或工厂函数构造最小可用数据。
- 通过 vi.mock 统一返回确定性的 API 响应。
- 每次测试前清理持久化存储,避免污染。
- 后端
- 使用静态数据或工厂方法构造入参。
- 对外部依赖(数据库/JWT)使用 Mockito 返回预设值。
- 集成测试建议使用独立测试库或内存库,避免影响生产数据。
[本节为通用指导,不直接分析具体源码文件]
常见场景示例指引
- 组件测试:见 tests/components/input.spec.js,覆盖多模式、事件、边界。
- 页面集成测试:见 tests/views/login.spec.js,验证登录流程与路由跳转。
- 服务层测试:见 tests/services/http.spec.js,验证拦截器与错误处理。
- 后端服务测试:见 service/AuthServiceTests.java,验证登录逻辑与 JWT 生成。
章节来源