Files
workspace/code/fms/.qoder/repowiki/zh/content/开发指南/测试指南.md
T
2026-08-23 21:02:41 +08:00

17 KiB
Raw Blame History

测试指南

**本文引用的文件** - [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)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本指南面向 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

图表来源

章节来源

核心组件

  • 前端测试基础设施
    • 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 外部依赖,反射注入被测对象字段,断言业务逻辑。

章节来源

架构总览

前后端测试分层与协作关系如下:

  • 前端
    • 单元/组件测试: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 : 服务/控制器用例结果

图表来源

详细组件分析

前端测试环境与工具链

  • 环境初始化
    • 全局 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 并设置期望。
    • 反射注入失败:确保字段名与类型匹配。

章节来源

结论

本项目已形成清晰的前后端测试体系:前端以 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 生成。

章节来源