Sinon.js:无法模拟 node.js 网络对象

Posted

技术标签:

【中文标题】Sinon.js:无法模拟 node.js 网络对象【英文标题】:Sinon.js: cannot mock node.js net object 【发布时间】:2021-11-24 13:49:59 【问题描述】:

我对测试很陌生,所以这个问题可能很简单......但我仍然需要一些帮助:

我有一个 node.js 服务器:

const net = require("net");
const Canvas = require("./canvas");

server.on("connection", (socket) => 
  const canvas = (new Canvas(socket));
  ...
);

server.listen(8124);

在 canvas.js 文件中:

class Canvas 
  constructor(socket) 
    this.socket = socket;
  
  
  disconnect() 
    this.socket.end();
    this.socket.destroy();
  

我正在尝试测试断开功能,并尝试模拟套接字对象的方法:

const Canvas = ...
const expect = require("expect");
const sinon = require("sinon");

describe('Canvas', () => 
  const fakeSocket = 
    end: () => ,
    destroy: () => ,
    write: () => ,
  ;

  let canvasObj;
  const mock = sinon.mock(fakeSocket);

  beforeEach(() => 
    canvasObj = new Canvas(mock);
  );

  describe("disconnect", () => 
    it("calls the appropriate functions", () => 
      mock.expects("end").once();
      mock.expects("destroy").once();
      canvasObj.disconnect();
      mock.verify();
      expect(fakeSocket.end).toHaveBeenCalled();
      expect(fakeSocket.destroy).toHaveBeenCalled();
    );
  );
);

不幸的是,当我运行测试时,它显示 TypeError: this.socket.end is not a function。我有什么遗漏吗?

【问题讨论】:

【参考方案1】:

当我看到您的示例时,我能想到的可能的断开测试脚本有 2 个版本:

    使用 sinon.fake(),
// File: canvas.spec.js
const expect = require('expect');
const sinon = require('sinon');
const Canvas = require('./canvas');

describe('Canvas using sinon.fake()', () => 
  const fakeSocket = 
    end: sinon.fake(),
    destroy: sinon.fake(),
    write: sinon.fake(),
  ;

  let canvasObj;

  beforeEach(() => 
    canvasObj = new Canvas(fakeSocket);
  );

  describe('disconnect', () => 
    it('calls the appropriate functions', () => 
      canvasObj.disconnect();
      // Note: You can not directly use toHaveBeenCalled() because this is from jest expect, not sinon.
      expect(fakeSocket.end.calledOnce).toBe(true);
      expect(fakeSocket.destroy.calledOnce).toBe(true);
    );
  );
);

    使用 sinon.mock()
// File: canvas2.spec.js
const expect = require('expect');
const sinon = require('sinon');
const net = require('net');
const Canvas = require('./canvas');

describe('Canvas using sinon.mock()', () => 
  let canvasObj;
  const socket = new net.Socket();
  const mock = sinon.mock(socket);
  
  beforeEach(() => 
    // Note: Subject under test is socket, not mock.
    canvasObj = new Canvas(socket);
  );

  describe('disconnect', () => 
    it('calls the appropriate functions', () => 
      mock.expects('end').once();
      mock.expects('destroy').once();
      canvasObj.disconnect();
      mock.verify();
    );
  );
);

当我从终端使用 mocha 运行它时:

$ npx mocha *.spec.js


  Canvas using sinon.mock()
    disconnect
      ✔ calls the appropriate functions

  Canvas using sinon.fake()
    disconnect
      ✔ calls the appropriate functions


  2 passing (16ms)

补充说明:fake function / spy 被调用一次的 sinon 期望是:calledOnce 而不是 toHaveBeenCalled()。

【讨论】:

非常感谢!好像我把 sinon 和 jest 的语法搞混了。 如果我的回答有帮助,那么:请vote or accept it。

以上是关于Sinon.js:无法模拟 node.js 网络对象的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sinon js/loopback testlab 模拟来自 twilio-node 的 messages.create() 方法的返回值?

从网络/TCP/HTTP 连接的角度来看,Node.js 是如何工作的? WCF 可以模拟这个吗?

Pub/Sub:似乎无法让本地模拟器与 Node.js 一起使用

Socket.IO 对 Node.js 有啥作用

Node.js 网络套接字:无法连接到多个 IP

Sinon 窥探 WebSocket