# 测试框架 **本文引用的文件** - [jest.config.js](file://jest.config.js) - [jest.config.js](file://client/jest.config.js) - [jest.setup.js](file://client/jest.setup.js) - [package.json](file://package.json) - [package.json](file://client/package.json) - [httphandler.test.ts](file://test/httphandler.test.ts) - [websockethandler.test.ts](file://test/websockethandler.test.ts) - [signaling.test.js](file://client/test/signaling.test.js) - [mocksignaling.js](file://client/test/mocksignaling.js) - [peerconnection.test.js](file://client/test/peerconnection.test.js) - [peerconnectionmock.js](file://client/test/peerconnectionmock.js) - [resizeobservermock.js](file://client/test/resizeobservermock.js) - [testutils.js](file://client/test/testutils.js) - [sender.test.js](file://client/test/sender.test.js) - [httphandler.ts](file://src/class/httphandler.ts) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖分析](#依赖分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本指南面向视频流服务器项目的测试体系,系统性阐述测试策略与架构,覆盖单元测试、集成测试与端到端测试的组织方式;详解 Jest 测试框架在服务端与客户端的配置与使用,包括测试环境设置、模拟对象与工具库;提供 WebRTC 信令与数据通道输入远程控制等关键功能的测试示例;说明测试覆盖率要求与报告生成;总结测试最佳实践与调试技巧,并给出测试用例编写指南。 ## 项目结构 项目采用分层与按功能划分的组织方式: - 服务端(src):核心业务逻辑与 HTTP/WebSocket 信令处理 - 服务端测试(test):基于 Express 模拟与 WebSocket 模拟器的集成测试 - 客户端(client):前端 JS 模块与 WebRTC 交互逻辑 - 客户端测试(client/test):JSDOM 环境下的单元与集成测试,含 WebRTC 模拟与信令模拟 ```mermaid graph TB subgraph "服务端" S1["HTTP处理器
src/class/httphandler.ts"] S2["WebSocket处理器
src/class/websockethandler.ts"] end subgraph "服务端测试" T1["HTTP信令测试
test/httphandler.test.ts"] T2["WebSocket信令测试
test/websockethandler.test.ts"] end subgraph "客户端" C1["信令模块
client/src/signaling.js"] C2["WebRTC封装
client/src/peer.js"] C3["输入远程控制
client/src/inputremoting.js"] end subgraph "客户端测试" CT1["信令测试
client/test/signaling.test.js"] CT2["Peer连接测试
client/test/peerconnection.test.js"] CT3["发送器测试
client/test/sender.test.js"] CM1["信令模拟
client/test/mocksignaling.js"] CM2["Peer模拟
client/test/peerconnectionmock.js"] CU1["测试工具
client/test/testutils.js"] end T1 --> S1 T2 --> S2 CT1 --> C1 CT2 --> C2 CT3 --> C3 CT1 --> CM1 CT2 --> CM2 CT2 --> CU1 ``` 图表来源 - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) - [peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251) - [mocksignaling.js:1-225](file://client/test/mocksignaling.js#L1-L225) - [peerconnectionmock.js:1-316](file://client/test/peerconnectionmock.js#L1-L316) - [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800) 章节来源 - [jest.config.js:1-196](file://jest.config.js#L1-L196) - [jest.config.js:1-196](file://client/jest.config.js#L1-L196) - [package.json:1-60](file://package.json#L1-L60) - [package.json:1-19](file://client/package.json#L1-L19) ## 核心组件 - 测试运行器与配置 - 服务端 Jest 配置启用 TypeScript 转换、Node 环境、覆盖率收集与默认匹配规则 - 客户端 Jest 配置启用 JSDOM 环境、setupFilesAfterEnv 引入全局模拟与 WebRTC 模拟 - 测试工具与模拟 - 服务端:Express 模拟中间件与 WebSocket 模拟器,验证 HTTP/WebSocket 信令流程 - 客户端:JSDOM 环境下注入 fetch、TextEncoder/Decoder、RTCPeerConnection 及 ResizeObserver 的模拟实现 - 信令模拟:MockSignaling 与 MockPublic/PrivateSignalingManager,支持公共/私有模式下的信令广播与连接管理 - WebRTC 模拟:PeerConnectionMock、SessionDescriptionMock、IceCandidateMock,覆盖 SDP 描述、ICE 候选、事件触发与状态机 - 工具库:waitFor、sleep、getRTCConfiguration 等,支撑异步等待与测试配置 - 关键模块测试 - HTTP 信令:会话创建、连接创建、offer/answer/candidate 收发、断开清理与超时回收 - WebSocket 信令:连接建立、消息转发、断开通知与多客户端广播 - 信令集成:公共/私有模式下跨客户端的信令收发与连接极性判定 - WebRTC Peer:addTrack/addTransceiver/createDataChannel、协商事件、候选收集、错误状态抛出 - 输入远程控制:鼠标/键盘/触摸事件捕获与 RTC 数据通道发送 章节来源 - [jest.config.js:1-196](file://jest.config.js#L1-L196) - [jest.config.js:1-196](file://client/jest.config.js#L1-L196) - [jest.setup.js:1-35](file://client/jest.setup.js#L1-L35) - [mocksignaling.js:1-225](file://client/test/mocksignaling.js#L1-L225) - [peerconnectionmock.js:1-316](file://client/test/peerconnectionmock.js#L1-L316) - [resizeobservermock.js:1-18](file://client/test/resizeobservermock.js#L1-L18) - [testutils.js:1-39](file://client/test/testutils.js#L1-L39) - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) - [peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251) - [sender.test.js:1-143](file://client/test/sender.test.js#L1-L143) ## 架构总览 测试架构分为三层: - 单元测试层:针对纯函数与小模块(如工具函数、模型类),快速验证边界条件与异常分支 - 集成测试层:组合模块与外部依赖(Express 中间件、WebSocket 服务器),验证端到端流程 - 端到端测试层:启动真实服务进程,进行跨浏览器/设备的信令与媒体交互验证 ```mermaid sequenceDiagram participant Test as "测试用例" participant HTTP as "HTTP处理器
httphandler.ts" participant WS as "WebSocket处理器
websockethandler.ts" participant MockSig as "信令模拟
mocksignaling.js" participant Peer as "Peer连接模拟
peerconnectionmock.js" Test->>HTTP : "创建会话/连接" HTTP-->>Test : "返回JSON响应" Test->>MockSig : "创建连接/发送offer/answer/candidate" MockSig-->>Test : "触发connect/offer/answer/candidate事件" Test->>Peer : "onGotDescription/onGotCandidate" Peer-->>Test : "触发sendoffer/sendanswer/sendcandidate事件" Test->>WS : "WebSocket信令收发" WS-->>Test : "消息转发/断开通知" ``` 图表来源 - [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800) - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) - [mocksignaling.js:1-225](file://client/test/mocksignaling.js#L1-L225) - [peerconnectionmock.js:1-316](file://client/test/peerconnectionmock.js#L1-L316) ## 详细组件分析 ### 服务端 HTTP 信令测试(单元/集成) - 测试目标 - 会话生命周期:创建、检查、删除 - 连接生命周期:创建、断开、清理 - 信令消息:offer/answer/candidate 的收发与查询 - 模式差异:公共/私有模式下的连接极性与广播行为 - 超时机制:长时间无请求的会话清理 - 关键断言 - 响应状态码与 JSON 结构 - 会话内连接列表与消息队列 - 私有模式下仅配对连接可互相接收信令 - 异步与超时 - 使用定时器与延迟模拟,验证超时清理逻辑 ```mermaid flowchart TD Start(["开始"]) --> CreateSession["创建会话"] CreateSession --> CreateConn["创建连接"] CreateConn --> SendOffer["发送Offer"] SendOffer --> ReceiveOffer["接收Offer"] ReceiveOffer --> SendAnswer["发送Answer"] SendAnswer --> ReceiveAnswer["接收Answer"] ReceiveAnswer --> SendCandidate["发送Candidate"] SendCandidate --> ReceiveCandidate["接收Candidate"] ReceiveCandidate --> DeleteConn["删除连接"] DeleteConn --> Cleanup["清理会话/断开通知"] Cleanup --> End(["结束"]) ``` 图表来源 - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800) 章节来源 - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800) ### 服务端 WebSocket 信令测试(集成) - 测试目标 - 多客户端连接与消息广播 - 私有模式下仅配对连接可互相接收信令 - 断开连接时双向通知 - 关键断言 - WebSocket 消息协议字段(from/to/type/data) - 消息到达顺序与数量 ```mermaid sequenceDiagram participant C1 as "客户端1" participant C2 as "客户端2" participant WS as "WebSocket服务器" C1->>WS : "connect(connectionId)" WS-->>C1 : "connect(own)" WS-->>C2 : "connect(other)" C1->>WS : "offer({connectionId,sdp})" WS-->>C2 : "offer({from,to,type,data})" C2->>WS : "answer({connectionId,sdp})" WS-->>C1 : "answer({from,to,type,data})" C1->>WS : "disconnect(connectionId)" WS-->>C1 : "disconnect" WS-->>C2 : "disconnect" ``` 图表来源 - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) 章节来源 - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) ### 客户端信令测试(集成/端到端) - 测试目标 - 公共/私有模式下信令收发与连接极性 - HTTP 与 WebSocket 两种信令通道 - 本地 MockSignaling 与真实服务进程的对比 - 关键断言 - connect/offer/answer/candidate 事件的 detail 字段 - 断开事件触发次数与 connectionId 匹配 - 端到端验证 - 通过 jest-dev-server 启动服务进程,使用真实 Signaling/WebSocketSignaling 进行连通性测试 ```mermaid sequenceDiagram participant T as "测试用例" participant M as "MockSignaling" participant S as "Signaling(HTTP)" participant W as "WebSocketSignaling" participant P as "服务进程" T->>M : "start/createConnection/sendOffer" M-->>T : "dispatchEvent(connect/offer/answer/candidate)" T->>S : "start/createConnection/sendOffer" S->>P : "HTTP请求" P-->>S : "响应/消息存储" T->>W : "start/createConnection/sendOffer" W->>P : "WebSocket消息" P-->>W : "消息转发" ``` 图表来源 - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) - [mocksignaling.js:1-225](file://client/test/mocksignaling.js#L1-L225) 章节来源 - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) - [mocksignaling.js:1-225](file://client/test/mocksignaling.js#L1-L225) ### WebRTC Peer 连接测试(单元/集成) - 测试目标 - 构造函数初始化与事件监听器绑定 - addTrack/addTransceiver/createDataChannel 触发协商 - onGotDescription/onGotCandidate 的事件与状态变化 - 候选收集与错误状态抛出 - 关键断言 - 发送 offer/answer/candidate 的事件详情 - negotiated 事件触发时机 - 候选未被接受的边界条件 ```mermaid classDiagram class Peer { +connectionId +pc +addEventListener(event, handler) +close() +addTrack(connectionId, track) +addTransceiver(connectionId, kind) +createDataChannel(connectionId, label) +onGotDescription(connectionId, desc) +onGotCandidate(connectionId, candidate) } class PeerConnectionMock { +localDescription +remoteDescription +addTrack(track) +addTransceiver(kind) +createDataChannel(label) +setLocalDescription(desc) +setRemoteDescription(desc) +addIceCandidate(candidate) +close() } Peer --> PeerConnectionMock : "使用" ``` 图表来源 - [peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251) - [peerconnectionmock.js:1-316](file://client/test/peerconnectionmock.js#L1-L316) 章节来源 - [peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251) - [peerconnectionmock.js:1-316](file://client/test/peerconnectionmock.js#L1-L316) ### 输入远程控制测试(单元) - 测试目标 - 设备注册与事件订阅 - 鼠标/键盘/触摸事件序列化与发送 - RTC 数据通道状态与发送调用 - 关键断言 - 设备数量与事件回调注册 - 数据通道 send 调用次数与 ArrayBuffer 内容 章节来源 - [sender.test.js:1-143](file://client/test/sender.test.js#L1-L143) ## 依赖分析 - 测试运行与环境 - 服务端:Jest + ts-jest + @jest-mock/express + jest-websocket-mock - 客户端:Jest + jest-environment-jsdom + jest-dev-server + node-fetch - 模拟与工具 - WebRTC 模拟:RTCPeerConnection、SessionDescription、IceCandidate - DOM/ResizeObserver 模拟:JSDOM 环境缺失时的 polyfill - 信令模拟:MockSignaling 与管理器 - 工具函数:等待、睡眠、唯一 ID、RTC 配置 ```mermaid graph LR Jest["Jest"] --> TS["ts-jest"] Jest --> JSDOM["jest-environment-jsdom"] Jest --> DevServer["jest-dev-server"] Jest --> WS["jest-websocket-mock"] Client["客户端测试"] --> JSDOM Client --> DevServer Client --> Fetch["node-fetch"] Server["服务端测试"] --> ExpressMock["@jest-mock/express"] Server --> WS ``` 图表来源 - [jest.config.js:1-196](file://jest.config.js#L1-L196) - [jest.config.js:1-196](file://client/jest.config.js#L1-L196) - [package.json:1-60](file://package.json#L1-L60) - [package.json:1-19](file://client/package.json#L1-L19) 章节来源 - [jest.config.js:1-196](file://jest.config.js#L1-L196) - [jest.config.js:1-196](file://client/jest.config.js#L1-L196) - [package.json:1-60](file://package.json#L1-L60) - [package.json:1-19](file://client/package.json#L1-L19) ## 性能考虑 - 测试并发与超时 - 客户端测试配置了较短的 testTimeout,避免长耗时阻塞 - 使用延迟与等待函数替代硬编码 sleep,提升稳定性 - 覆盖率与报告 - 启用 v8 覆盖收集与输出目录,建议结合 CI 生成 LCOV 报告 - 对关键路径(HTTP/WebSocket 信令、WebRTC 状态机)优先保证高覆盖率 - 端到端成本 - 真实服务进程启动与关闭需注意资源释放,Linux 平台增加等待时间 章节来源 - [jest.config.js:170-171](file://client/jest.config.js#L170-L171) - [jest.config.js:20-26](file://jest.config.js#L20-L26) - [jest.config.js:33-34](file://jest.config.js#L33-L34) ## 故障排查指南 - 环境变量与脚本 - 服务端脚本使用 Jest 直接执行 test/*.ts;确保 ts-jest 与 TypeScript 配置正确 - 客户端脚本使用 Node VM 模块运行 Jest;确保 package.json 中的脚本与依赖一致 - JSDOM 缺失 API - 在 jest.setup.js 中注入 fetch、TextEncoder/Decoder、RTCPeerConnection、ResizeObserver - 若仍报错,确认 jest-environment-jsdom 版本与 jest.setup.js 的引入顺序 - WebRTC 模拟问题 - 确认 PeerConnectionMock 的事件回调与状态机逻辑与实际浏览器行为一致 - 对于 InvalidStateError 等异常,需在测试中显式断言 - 信令模拟一致性 - MockSignaling 与真实服务端的字段保持一致(connectionId、sdp、polite、candidate 等) - 私有模式下仅配对连接可互相接收信令,否则应断言未收到 - 端到端启动失败 - 检查 jest-dev-server 的命令拼接与端口占用 - Linux 平台在 teardown 后增加等待时间,避免进程残留导致后续测试失败 章节来源 - [package.json:5-12](file://package.json#L5-L12) - [package.json:5-8](file://client/package.json#L5-L8) - [jest.setup.js:1-35](file://client/jest.setup.js#L1-L35) - [signaling.test.js:23-65](file://client/test/signaling.test.js#L23-L65) - [peerconnectionmock.js:157-160](file://client/test/peerconnectionmock.js#L157-L160) ## 结论 本项目采用“单元测试 + 集成测试 + 端到端测试”的分层策略,结合 Jest 与多种模拟技术,实现了对 HTTP/WebSocket 信令、WebRTC 连接与输入远程控制的全面覆盖。通过 MockSignaling、PeerConnectionMock 与工具库,测试在可控环境中复现复杂交互;通过公共/私有模式与超时清理逻辑的验证,确保系统在真实场景下的健壮性。 ## 附录 ### 测试策略与组织 - 单元测试 - 针对纯函数与小模块,断言边界与异常 - 示例:工具函数、模型类、状态转换 - 集成测试 - 组合模块与外部依赖,验证流程完整性 - 示例:HTTP 信令、WebSocket 信令、WebRTC 状态机 - 端到端测试 - 启动真实服务进程,验证跨客户端交互 - 示例:HTTP/WebSocket 信令通道、真实浏览器环境 章节来源 - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) ### Jest 配置与使用要点 - 服务端 - 启用 ts-jest 转换,Node 环境,收集覆盖率,匹配 test/*.ts - 客户端 - JSDOM 环境,setupFilesAfterEnv 引入全局模拟,匹配 client/test/**/*.test.js - 脚本 - 服务端:npm/yarn test 指向 Jest 并传入测试文件 - 客户端:使用 Node VM 模块运行 Jest 章节来源 - [jest.config.js:1-196](file://jest.config.js#L1-L196) - [jest.config.js:1-196](file://client/jest.config.js#L1-L196) - [package.json:5-12](file://package.json#L5-L12) - [package.json:5-8](file://client/package.json#L5-L8) ### 覆盖率要求与报告 - 覆盖率收集 - 开启 collectCoverage,输出目录为 coverage,提供 v8 覆盖器 - 报告生成 - 建议在 CI 中生成 LCOV 报告并与平台集成 - 要求建议 - 关键模块(HTTP/WebSocket 信令、WebRTC 状态机)覆盖率不低于 80% - 重要分支与异常路径必须覆盖 章节来源 - [jest.config.js:20-26](file://jest.config.js#L20-L26) - [jest.config.js:33-34](file://jest.config.js#L33-L34) ### WebRTC 功能测试示例 - 信令处理测试 - 使用 MockSignaling 验证公共/私有模式下的 offer/answer/candidate 分发 - 使用 jest-websocket-mock 验证 WebSocket 信令通道 - Peer 连接测试 - 使用 PeerConnectionMock 验证 addTrack/addTransceiver/createDataChannel 的事件触发 - 验证 onGotDescription/onGotCandidate 的状态变化与候选收集 章节来源 - [mocksignaling.js:1-225](file://client/test/mocksignaling.js#L1-L225) - [peerconnectionmock.js:1-316](file://client/test/peerconnectionmock.js#L1-L316) - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) ### 客户端测试与服务器端测试示例 - 客户端 - 信令:公共/私有模式、HTTP/WebSocket 三种通道 - WebRTC:构造、关闭、事件触发、候选收集 - 输入远程控制:事件捕获与发送 - 服务器端 - HTTP 信令:会话/连接生命周期、消息收发、超时清理 - WebSocket 信令:多客户端广播、断开通知 章节来源 - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) - [peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251) - [sender.test.js:1-143](file://client/test/sender.test.js#L1-L143) - [httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510) - [websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191) ### 测试最佳实践与调试技巧 - 最佳实践 - 使用 describe/it 分层组织测试,命名清晰表达意图 - 使用 beforeEach/beforeAll 准备测试上下文,避免重复代码 - 对异步流程使用 waitFor/sleep 替代固定延时 - 对模拟对象进行 spy/restore,避免副作用影响其他测试 - 调试技巧 - 在 jest.setup.js 注入必要 polyfill,减少环境差异 - 使用 console.log 或断点定位事件触发时机 - 对 WebSocket 与 HTTP 信令分别断言消息字段与数量 章节来源 - [jest.setup.js:1-35](file://client/jest.setup.js#L1-L35) - [signaling.test.js:1-485](file://client/test/signaling.test.js#L1-L485) - [peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251)