我如何监视注入的构造函数?

How do I spy on an injected constructor?

我有一个 Manager 大量使用 serialport 模块,并且想 运行 使用模拟版本的串口进行单元测试。我重写了我的管理器模块以利用依赖注入:

// file: manager.js

function Manager(SerialPort, device, baudRate) {
  this._device = device;
  this._serialPort = new SerialPort(device, {autoOpen: false, baudRate: baudRate })
};
Manager.prototype.constructor = Manager;

现在我想测试一下是否将正确的参数传递给了 new SerialPort() 调用。我一直在研究如何正确 stub/mock 构造函数。这是我目前所拥有的:

// file: manager-test.js

function MockSerialPort(device, options) {}

describe('Manager', function() {
  describe('constructor', function() {
    it('instantiates a serial port with correct baud rate', function() {
      const manager = new Manager(MockSerialPort, '/dev/tty', 9600);
      expect(<something>).to.be.calledWith('/dev/tty', {autoOpen: false, baudRate: 9600});
    });
  });
});

很明显我有几个洞

在我的脑海里,哎呀,不,我的意思是

在我的代码中。我需要填写什么才能完成此测试?

更新

正如@cdhowie 指出的那样,如果我可以将实例化的 SerialPort 对象传递给管理器,生活会更轻松。由于一些误导性文档,我认为使用 SerialPort API 是不可能的,但多亏了他的帮助,现在的实现看起来像:

function Manager(serialPort) {
  this._serialPort = serialPort;
}
Manager.prototype.constructor = Manager;

这意味着在我的测试中,我只是创建了一些外观、游泳和嘎嘎声都像 SerialPort 对象的东西。存根和监视就变得微不足道了。

只需使用一个将其参数存储在测试范围内的匿名函数:

let ctorArgs;
const manager = new Manager(function () {
    ctorArgs = Array.prototype.slice.call(arguments);
}, '/dev/tty', 9600);

// Assert against the contents of ctorArgs

旁注:为什么要将构造函数和参数传递给 Manager 而不是仅传递构造的 SerialPort 对象?除非 Manager 需要创建多个具有相同参数的对象,否则将创建对象的负担交给它似乎有点傻。