【问题标题】:Sinon.js: cannot mock node.js net objectSinon.js:无法模拟 node.js 网络对象
【发布时间】: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。我有什么遗漏吗?

【问题讨论】:

    标签: node.js sockets mocha.js sinon


    【解决方案1】:

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

    1. 使用 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);
        });
      });
    });
    
    
    1. 使用 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
    猜你喜欢
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多