单元测试中伪造 websocket 连接的核心是用 mock 替换全局 websocket 构造函数或实现可交互的 mock 类,以控制连接状态、触发事件并验证行为,避免真实网络请求。

在单元测试中伪造 WebSocket 连接,核心思路是**用可控制的模拟对象(Mock)替换原生 WebSocket 构造函数或实例方法**,使其不真实发起网络请求,同时能响应测试逻辑(如触发 onopen、接收/发送消息、模拟错误等)。
1. 替换全局 WebSocket 构造函数(推荐)
这是最常用且侵入性最小的方式。在测试前用 Jest 或其他测试框架 mock 全局 WebSocket,让所有新建连接都返回可控的模拟实例。
- 用
jest.mock('websocket', ...)不适用——因为原生WebSocket是全局对象,不是模块 - 正确做法:在测试文件顶部或
beforeEach中执行:
global.WebSocket = jest.fn(() => ({
readyState: WebSocket.OPEN,
send: jest.fn(),
close: jest.fn(),
addEventListener: jest.fn(),
dispatchEvent: jest.fn()
})); - 注意:需手动模拟事件触发逻辑(例如调用
onopen),或使用更完整的 mock 实现(见下一点)
2. 使用完整可交互的 Mock WebSocket 类
为支持事件回调(如 onmessage、onerror)和主动触发行为,建议定义一个轻量级模拟类:
- 在测试辅助文件中定义:
class MockWebSocket {
constructor(url) {
this.url = url;
this.readyState = WebSocket.CONNECTING;
this.onopen = null;
this.onmessage = null;
this.onerror = null;
this.onclose = null;
// 模拟连接成功
setTimeout(() => {
this.readyState = WebSocket.OPEN;
if (this.onopen) this.onopen({ type: 'open' });
}, 0);
}
send(data) { /* 记录或转发 */ }
close() { this.readyState = WebSocket.CLOSED; }
} - 然后在测试前注入:
global.WebSocket = MockWebSocket; - 这样你的被测代码就能正常绑定
ws.onmessage = ...,你也能在测试中调用ws.dispatchEvent(new MessageEvent(...))或直接调用ws.onmessage(...)触发处理逻辑
3. 在测试中验证行为与交互
伪造之后,重点是验证组件是否正确使用了 WebSocket:
- 检查是否用预期 URL 创建了连接:
expect(global.WebSocket).toHaveBeenCalledWith('ws://localhost:8080'); - 验证是否监听了消息:
const ws = new WebSocket();
expect(typeof ws.onmessage).toBe('function'); - 模拟收到消息并断言副作用(如状态更新、函数调用):
ws.onmessage({ data: JSON.stringify({ type: 'update', value: 42 }) });
expect(handleUpdate).toHaveBeenCalledWith({ type: 'update', value: 42 }); - 测试错误场景:手动设置
ws.readyState = WebSocket.CLOSED,再调用ws.send(),检查是否抛出异常或进入降级逻辑
4. 注意事项与常见坑
- 不要依赖真实网络:确保测试环境禁用真实连接(如通过环境变量或配置跳过初始化)
-
清理全局 mock:用
afterEach(() => { delete global.WebSocket; })或jest.restoreAllMocks()防止测试间污染 - 区分构造函数 mock 和实例 mock:只 mock 构造函数还不够,还需控制实例行为;建议统一用类 mock 方式
-
兼容浏览器与 Node.js:Node 环境无原生
WebSocket,需配合ws或mock-socket库;但单元测试中一般仍 mock 全局接口保持一致性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











