You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Sinon正确模拟websockets/ws?遇TypeError问题求助

如何用Sinon正确模拟websockets/ws对象以测试WebSocket事件处理逻辑?

问题背景

我有C#开发背景,习惯用Moq类库模拟接口并验证调用。现在尝试用Sinon模拟websockets/ws库,想在无需实际连接的情况下测试应用的WebSocket事件处理逻辑,但运行测试时遇到错误:

TypeError: Attempted to wrap undefined property on as function

测试代码示例:

const WebSocket = require('ws');
const sinon = require('sinon');
const webSocket = sinon.mock(WebSocket);
webSocket.expects('on').withArgs(sinon.match.any, sinon.match.any);

const subject = new MyClass(logger, webSocket);

应用中的调用代码:

this._webSocket.on("open", () => { this.onWebSocketOpen(); });

问题根源

你踩的坑其实是Sinon和Moq在模拟对象时的一个关键差异:你用sinon.mock(WebSocket)模拟的是WebSocket类本身,但on方法是WebSocket实例才有的属性,类本身并没有这个方法,所以Sinon会报错说找不到要包装的on属性。

正确的模拟方案

根据你的代码场景(把WebSocket实例传入MyClass),这里有两种最常用的正确做法:

1. 直接模拟WebSocket实例

这是最贴合你当前代码结构的方式——直接创建一个模拟的WebSocket实例,然后传给MyClass:

const sinon = require('sinon');

// 创建一个空的模拟对象,专门用来模拟WebSocket实例
const wsMock = sinon.mock();
// 给这个模拟对象添加对`on`方法的调用预期
wsMock.expects('on')
  .withArgs('open', sinon.match.func) // 验证参数:第一个是'open',第二个是函数
  .once(); // 可以指定预期被调用的次数,让测试更严谨

// 把模拟实例传给你的MyClass
const subject = new MyClass(logger, wsMock);

// 执行完你的测试逻辑后,验证所有预期是否都被满足
wsMock.verify();

2. 用Stub替代Mock(更灵活的验证方式)

如果你不需要严格的调用顺序,只是想验证on方法是否被正确调用,用sinon.stub会更灵活:

const sinon = require('sinon');

// 创建一个stub对象,然后给它添加`on`方法的stub
const wsStub = {};
wsStub.on = sinon.stub();

// 传入MyClass
const subject = new MyClass(logger, wsStub);

// 执行测试逻辑后,验证调用情况
sinon.assert.calledOnce(wsStub.on); // 验证on被调用了一次
sinon.assert.calledWith(wsStub.on, 'open', sinon.match.func); // 验证调用参数正确

额外场景:如果MyClass内部创建WebSocket实例

如果你的MyClass是自己内部通过new WebSocket(...)创建实例,而不是外部传入,那你需要模拟WebSocket的构造函数,让它返回你预先准备好的模拟实例:

const WebSocket = require('ws');
const sinon = require('sinon');

// 先创建一个模拟的实例
const wsInstanceMock = sinon.mock();
wsInstanceMock.expects('on').withArgs('open', sinon.match.func);

// 存根WebSocket构造函数,让它返回我们的模拟实例
const wsConstructorStub = sinon.stub(global, 'WebSocket').returns(wsInstanceMock);

// 初始化MyClass(它内部会调用new WebSocket())
const subject = new MyClass(logger);

// 验证预期
wsInstanceMock.verify();
// 测试结束后别忘了清理存根,避免影响其他测试
wsConstructorStub.restore();

内容的提问来源于stack exchange,提问作者BnMcG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:44:10