20 KiB
20 KiB
测试框架
**本文引用的文件** - [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)目录
简介
本指南面向视频流服务器项目的测试体系,系统性阐述测试策略与架构,覆盖单元测试、集成测试与端到端测试的组织方式;详解 Jest 测试框架在服务端与客户端的配置与使用,包括测试环境设置、模拟对象与工具库;提供 WebRTC 信令与数据通道输入远程控制等关键功能的测试示例;说明测试覆盖率要求与报告生成;总结测试最佳实践与调试技巧,并给出测试用例编写指南。
项目结构
项目采用分层与按功能划分的组织方式:
- 服务端(src):核心业务逻辑与 HTTP/WebSocket 信令处理
- 服务端测试(test):基于 Express 模拟与 WebSocket 模拟器的集成测试
- 客户端(client):前端 JS 模块与 WebRTC 交互逻辑
- 客户端测试(client/test):JSDOM 环境下的单元与集成测试,含 WebRTC 模拟与信令模拟
graph TB
subgraph "服务端"
S1["HTTP处理器<br/>src/class/httphandler.ts"]
S2["WebSocket处理器<br/>src/class/websockethandler.ts"]
end
subgraph "服务端测试"
T1["HTTP信令测试<br/>test/httphandler.test.ts"]
T2["WebSocket信令测试<br/>test/websockethandler.test.ts"]
end
subgraph "客户端"
C1["信令模块<br/>client/src/signaling.js"]
C2["WebRTC封装<br/>client/src/peer.js"]
C3["输入远程控制<br/>client/src/inputremoting.js"]
end
subgraph "客户端测试"
CT1["信令测试<br/>client/test/signaling.test.js"]
CT2["Peer连接测试<br/>client/test/peerconnection.test.js"]
CT3["发送器测试<br/>client/test/sender.test.js"]
CM1["信令模拟<br/>client/test/mocksignaling.js"]
CM2["Peer模拟<br/>client/test/peerconnectionmock.js"]
CU1["测试工具<br/>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
- websockethandler.test.ts:1-191
- signaling.test.js:1-485
- peerconnection.test.js:1-251
- mocksignaling.js:1-225
- peerconnectionmock.js:1-316
- httphandler.ts:1-800
章节来源
核心组件
- 测试运行器与配置
- 服务端 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
- jest.config.js:1-196
- jest.setup.js:1-35
- mocksignaling.js:1-225
- peerconnectionmock.js:1-316
- resizeobservermock.js:1-18
- testutils.js:1-39
- httphandler.test.ts:1-510
- websockethandler.test.ts:1-191
- signaling.test.js:1-485
- peerconnection.test.js:1-251
- sender.test.js:1-143
架构总览
测试架构分为三层:
- 单元测试层:针对纯函数与小模块(如工具函数、模型类),快速验证边界条件与异常分支
- 集成测试层:组合模块与外部依赖(Express 中间件、WebSocket 服务器),验证端到端流程
- 端到端测试层:启动真实服务进程,进行跨浏览器/设备的信令与媒体交互验证
sequenceDiagram
participant Test as "测试用例"
participant HTTP as "HTTP处理器<br/>httphandler.ts"
participant WS as "WebSocket处理器<br/>websockethandler.ts"
participant MockSig as "信令模拟<br/>mocksignaling.js"
participant Peer as "Peer连接模拟<br/>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
- httphandler.test.ts:1-510
- websockethandler.test.ts:1-191
- mocksignaling.js:1-225
- peerconnectionmock.js:1-316
详细组件分析
服务端 HTTP 信令测试(单元/集成)
- 测试目标
- 会话生命周期:创建、检查、删除
- 连接生命周期:创建、断开、清理
- 信令消息:offer/answer/candidate 的收发与查询
- 模式差异:公共/私有模式下的连接极性与广播行为
- 超时机制:长时间无请求的会话清理
- 关键断言
- 响应状态码与 JSON 结构
- 会话内连接列表与消息队列
- 私有模式下仅配对连接可互相接收信令
- 异步与超时
- 使用定时器与延迟模拟,验证超时清理逻辑
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(["结束"])
图表来源
章节来源
服务端 WebSocket 信令测试(集成)
- 测试目标
- 多客户端连接与消息广播
- 私有模式下仅配对连接可互相接收信令
- 断开连接时双向通知
- 关键断言
- WebSocket 消息协议字段(from/to/type/data)
- 消息到达顺序与数量
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"
图表来源
章节来源
客户端信令测试(集成/端到端)
- 测试目标
- 公共/私有模式下信令收发与连接极性
- HTTP 与 WebSocket 两种信令通道
- 本地 MockSignaling 与真实服务进程的对比
- 关键断言
- connect/offer/answer/candidate 事件的 detail 字段
- 断开事件触发次数与 connectionId 匹配
- 端到端验证
- 通过 jest-dev-server 启动服务进程,使用真实 Signaling/WebSocketSignaling 进行连通性测试
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 : "消息转发"
图表来源
章节来源
WebRTC Peer 连接测试(单元/集成)
- 测试目标
- 构造函数初始化与事件监听器绑定
- addTrack/addTransceiver/createDataChannel 触发协商
- onGotDescription/onGotCandidate 的事件与状态变化
- 候选收集与错误状态抛出
- 关键断言
- 发送 offer/answer/candidate 的事件详情
- negotiated 事件触发时机
- 候选未被接受的边界条件
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 : "使用"
图表来源
章节来源
输入远程控制测试(单元)
- 测试目标
- 设备注册与事件订阅
- 鼠标/键盘/触摸事件序列化与发送
- RTC 数据通道状态与发送调用
- 关键断言
- 设备数量与事件回调注册
- 数据通道 send 调用次数与 ArrayBuffer 内容
章节来源
依赖分析
- 测试运行与环境
- 服务端: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 配置
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
图表来源
章节来源
性能考虑
- 测试并发与超时
- 客户端测试配置了较短的 testTimeout,避免长耗时阻塞
- 使用延迟与等待函数替代硬编码 sleep,提升稳定性
- 覆盖率与报告
- 启用 v8 覆盖收集与输出目录,建议结合 CI 生成 LCOV 报告
- 对关键路径(HTTP/WebSocket 信令、WebRTC 状态机)优先保证高覆盖率
- 端到端成本
- 真实服务进程启动与关闭需注意资源释放,Linux 平台增加等待时间
章节来源
故障排查指南
- 环境变量与脚本
- 服务端脚本使用 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
- package.json:5-8
- jest.setup.js:1-35
- signaling.test.js:23-65
- peerconnectionmock.js:157-160
结论
本项目采用“单元测试 + 集成测试 + 端到端测试”的分层策略,结合 Jest 与多种模拟技术,实现了对 HTTP/WebSocket 信令、WebRTC 连接与输入远程控制的全面覆盖。通过 MockSignaling、PeerConnectionMock 与工具库,测试在可控环境中复现复杂交互;通过公共/私有模式与超时清理逻辑的验证,确保系统在真实场景下的健壮性。
附录
测试策略与组织
- 单元测试
- 针对纯函数与小模块,断言边界与异常
- 示例:工具函数、模型类、状态转换
- 集成测试
- 组合模块与外部依赖,验证流程完整性
- 示例:HTTP 信令、WebSocket 信令、WebRTC 状态机
- 端到端测试
- 启动真实服务进程,验证跨客户端交互
- 示例:HTTP/WebSocket 信令通道、真实浏览器环境
章节来源
Jest 配置与使用要点
- 服务端
- 启用 ts-jest 转换,Node 环境,收集覆盖率,匹配 test/*.ts
- 客户端
- JSDOM 环境,setupFilesAfterEnv 引入全局模拟,匹配 client/test/**/*.test.js
- 脚本
- 服务端:npm/yarn test 指向 Jest 并传入测试文件
- 客户端:使用 Node VM 模块运行 Jest
章节来源
覆盖率要求与报告
- 覆盖率收集
- 开启 collectCoverage,输出目录为 coverage,提供 v8 覆盖器
- 报告生成
- 建议在 CI 中生成 LCOV 报告并与平台集成
- 要求建议
- 关键模块(HTTP/WebSocket 信令、WebRTC 状态机)覆盖率不低于 80%
- 重要分支与异常路径必须覆盖
章节来源
WebRTC 功能测试示例
- 信令处理测试
- 使用 MockSignaling 验证公共/私有模式下的 offer/answer/candidate 分发
- 使用 jest-websocket-mock 验证 WebSocket 信令通道
- Peer 连接测试
- 使用 PeerConnectionMock 验证 addTrack/addTransceiver/createDataChannel 的事件触发
- 验证 onGotDescription/onGotCandidate 的状态变化与候选收集
章节来源
客户端测试与服务器端测试示例
- 客户端
- 信令:公共/私有模式、HTTP/WebSocket 三种通道
- WebRTC:构造、关闭、事件触发、候选收集
- 输入远程控制:事件捕获与发送
- 服务器端
- HTTP 信令:会话/连接生命周期、消息收发、超时清理
- WebSocket 信令:多客户端广播、断开通知
章节来源
- signaling.test.js:1-485
- peerconnection.test.js:1-251
- sender.test.js:1-143
- httphandler.test.ts:1-510
- websockethandler.test.ts:1-191
测试最佳实践与调试技巧
- 最佳实践
- 使用 describe/it 分层组织测试,命名清晰表达意图
- 使用 beforeEach/beforeAll 准备测试上下文,避免重复代码
- 对异步流程使用 waitFor/sleep 替代固定延时
- 对模拟对象进行 spy/restore,避免副作用影响其他测试
- 调试技巧
- 在 jest.setup.js 注入必要 polyfill,减少环境差异
- 使用 console.log 或断点定位事件触发时机
- 对 WebSocket 与 HTTP 信令分别断言消息字段与数量
章节来源