如何完美测试 AI 摘要通过 SSE 输出的打字效果?
前面两篇文章简单介绍了如何只用Nextjs在本地模拟 SSE 实现打字效果和通过Streamdown优雅地解析输出 AI 返回的Markdown文本,接下来就是如何测试了。
前面两篇文章简单介绍了如何只用 Nextjs
在本地模拟 SSE 实现打字效果和通过 Streamdown
优雅地解析输出 AI 返回的 Markdown
文本,接下来就是如何测试了。
Mock 框架
Mock 框架有很多,个人倾向使用 Mock Service Worker (MSW)
来测 AI 相关的功能,在下面的详细对比中也有意将 MSW 放在第一位。
- MSW (Mock Service Worker)
- JSON Server
- WireMock
- Nock
- MirageJS
框架对比
1. 架构设计与工作原理
框架 | 工作原理 | 优点 | 缺点 |
---|---|---|---|
MSW | 基于 Service Worker API 拦截网络请求 | • 在网络层面拦截,透明度高 • 支持浏览器和 Node.js 环境 • 不侵入业务代码 |
• 需要理解 Service Worker 概念 • 在某些环境下配置相对复杂 |
JSON Server | 启动独立的 REST API 服务器 | • 零配置快速启动 • 自动生成 CRUD 接口 • 支持关系数据和查询 |
• 仅限于 REST API • 功能相对简单 • 需要独立端口 |
WireMock | 基于 HTTP 服务器的 Mock 框架 | • 功能强大,支持复杂场景 • 丰富的匹配规则 • 支持状态管理和故障注入 |
• 主要面向 Java 生态 • 配置复杂 • 资源消耗较大 |
Nock | HTTP 请求拦截库 | • 专门针对 Node.js 环境 • API 简洁直观 • 测试友好 |
• 仅支持 Node.js • 不支持浏览器环境 • 功能相对单一 |
MirageJS | 客户端服务器模拟框架 | • 提供完整的数据层模拟 • 支持数据库关系 • 内置 ORM |
• 学习曲线陡峭 • 配置复杂 • 体积较大 |
2. 开发体验与易用性
框架 | 学习成本 | 配置复杂度 | API 设计 | TypeScript 支持 | 热重载 | 调试体验 |
---|---|---|---|---|---|---|
MSW | 中等 | 中等 | 声明式,直观 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
JSON Server | 极低 | 极简 | 约定优于配置 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
WireMock | 高 | 复杂 | 功能丰富但冗长 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
Nock | 低 | 简单 | 链式调用,简洁 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
MirageJS | 高 | 复杂 | ORM 风格 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
详细说明:
- MSW: 声明式 API 设计优秀,TypeScript 支持完善,但 Service Worker 调试相对复杂
- JSON Server: 学习成本最低,一行命令启动,但功能相对基础
- WireMock: 企业级功能完善,但配置复杂,主要面向 Java 开发者
- Nock: API 简洁明了,测试友好,但仅限 Node.js 环境
- MirageJS: 功能最全面,但学习曲线陡峭,配置最复杂
3. 性能表现
框架 | 启动速度 | 内存占用 | 响应延迟 | 并发处理 |
---|---|---|---|---|
MSW | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
JSON Server | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
WireMock | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
Nock | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
MirageJS | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
4. 功能覆盖度
功能特性 | MSW | JSON Server | WireMock | Nock | MirageJS |
---|---|---|---|---|---|
REST API | ✅ | ✅ | ✅ | ✅ | ✅ |
GraphQL | ✅ | ❌ | ❌ | ❌ | ✅ |
WebSocket/SSE | ✅ | ❌ | ❌ | ❌ | ❌ |
浏览器环境 | ✅ | ❌ | ❌ | ❌ | ✅ |
Node.js 环境 | ✅ | ✅ | ✅ | ✅ | ❌ |
请求录制回放 | ❌ | ❌ | ✅ | ❌ | ❌ |
故障注入 | ✅ | ❌ | ✅ | ✅ | ✅ |
延迟模拟 | ✅ | ❌ | ✅ | ❌ | ✅ |
状态管理 | 基础 | ❌ | ✅ | ❌ | ✅ |
数据持久化 | ❌ | ✅ | ✅ | ❌ | ❌ |
数据关系建模 | ❌ | 基础 | ❌ | ❌ | ✅ |
自定义中间件 | ✅ | ✅ | ✅ | ❌ | ✅ |
代理模式 | ❌ | ❌ | ✅ | ❌ | ❌ |
TypeScript 支持 | ✅ | 部分 | 部分 | ✅ | ✅ |
热重载 | ✅ | ✅ | ✅ | ✅ | ✅ |
符号说明:
- ✅:完全支持
- 部分:部分支持
- 基础:基础功能
- ❌:不支持
5. 生态系统与社区支持
框架 | GitHub Stars | NPM 周下载量 | 社区活跃度 | 文档质量 | 维护状态 |
---|---|---|---|---|---|
MSW | 15.8k+ | 1.2M+ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 积极维护 |
JSON Server | 72k+ | 800k+ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 稳定维护 |
WireMock | 6.2k+ | N/A | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 积极维护 |
Nock | 12.6k+ | 1.8M+ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 稳定维护 |
MirageJS | 5.4k+ | 50k+ | ⭐⭐⭐ | ⭐⭐⭐⭐ | 维护缓慢 |
适合场景
🚀 适合 MSW 的场景:
- 现代前端应用开发(React、Vue、Angular)
- 同时支持开发和测试环境
- 模拟实时数据流(SSE、WebSocket)
- 统一的 Mock 解决方案
⚡ 适合 JSON Server 的场景:
- 快速原型验证
- 简单的 REST API Mock
- 最小学习成本
- 独立的 Mock 服务
🏢 适合 WireMock 的场景:
- 企业级功能(录制回放、故障注入)
- 微服务架构测试
- 复杂的网络场景模拟
- Java 技术栈集成
🧪 适合 Nock 的场景:
- Node.js 后端测试
- 精确的请求拦截验证
- 轻量级测试解决方案
- 与测试框架深度集成
🎯 适合 MirageJS 的场景:
- 完整的数据层模拟
- 复杂的数据关系建模
- 长期前端项目开发
- 离线开发能力
选择 MSW 的优势
- 架构先进: 基于 Service Worker 设计,在网络层面拦截请求,不侵入业务代码
- 跨环境支持: 同时支持浏览器和 Node.js 环境,一套代码多环境复用
- 开发体验: 优秀的 TypeScript 支持和现代化的 API 设计
- 功能完善: 支持 REST、GraphQL、实时数据流等多种协议
- 社区活跃: 持续的更新和丰富的生态系统
安装 MSW
演示基于 Nextjs
- 安装 MSW
// npm npm i msw --save-dev // yarn yarn add msw -D
- 额外的一步:生成浏览器端的
./public/mockServiceWorker.js
npx msw init public/
使用 MSW
目录结构和文件解释
MSW SSE Mock 项目 - 目录结构 =============================== 项目根目录: /mock-sse-by-msw ├── 📁 public/ # 静态文件目录 │ └── 📄 mockServiceWorker.js # MSW Service Worker 脚本,拦截浏览器请求 ├── 📁 src/ # 源代码目录 │ ├── 📁 app/ # Next.js App Router 目录 │ │ ├── 📄 globals.css # 全局 CSS 样式,应用于整个应用程序 │ │ ├── 📄 layout.tsx # 根布局组件,包住所有页面 │ │ └── 📄 page.tsx # 主页面组件,展示 SSE 功能演示 │ ├── 📁 components/ # 可复用的 React 组件目录 │ │ └── 📄 mockServer.tsx # Mock 服务器初始化组件 │ └── 📁 mock/ # MSW Mock 配置和处理器 │ ├── 📁 __fixture__/ # 测试数据目录 │ │ └── 📄 summaryTexts.js # SSE 流式传输模拟的示例文本数据 │ ├── 📄 browser.ts # MSW 浏览器端设置,用于拦截客户端请求 │ ├── 📄 handler.ts # MSW 请求处理器,定义 Mock API │ ├── 📄 initmock.ts # 开发环境 Mock 初始化逻辑 │ └── 📄 server.ts # MSW 服务器端设置,用于 Node.js 环境(测试) └── 📄 yarn.lock # Yarn 依赖锁定文件,用于包管理
开发工作流
- MSW Service Worker 在浏览器中拦截网络请求
- Mock 处理器提供真实的 API 响应
- SSE 端点逐字符流式传输数据
- React 组件消费实时数据流
- 开发服务器提供热重载即时更新
- 更改
./src/mock/__fixture__/summaryText.js
中的 Markdown 数据
- 更改
核心代码
在 MSW 中模拟 SSE (Server-Sent Events) handler
// ./src/mock/handler.ts export const handlers = [ // SSE (Server-Sent Events) handler http.get("/api/sse", ({ request }) => { const url = new URL(request.url); const interval =20; const summaryKey = url.searchParams.get('summary'); const maxCount = summaryKey && summaryArray[summaryKey].length || 10; const stream = new ReadableStream({ start(controller) { let counter = 0; const sendEvent = () => { let message = ""; // If summary key is provided and exists in summaryArray, use summary text if (summaryKey && summaryArray[summaryKey] && summaryArray[summaryKey][counter]) { message = summaryArray[summaryKey][counter]; } const data = { id: counter, message, timestamp: new Date().toISOString(), type: 'update', }; const eventData = `data: ${JSON.stringify(data)}\n\n`; controller.enqueue(new TextEncoder().encode(eventData)); counter++; if (counter < maxCount) { setTimeout(sendEvent, interval); // Send event with custom interval } else { // Send final event and close controller.enqueue(new TextEncoder().encode('data: {"type":"close","message":"Stream ended"}\n\n')); controller.close(); } }; // Send initial event sendEvent(); } }); return new HttpResponse(stream, { status: 200, headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Cache-Control' } }); }) ]
更多推荐
所有评论(0)