如何使用Sinon存根ES6类构造函数

时间:2017-10-06 15:09:08

标签: javascript sinon es6-class

我正在尝试使用Sinon的存根类构造函数。

常规方法的存根' omg'工作正常,但构造函数的存根未通过测试,并且真正的'调用构造函数而不是存根。

关于我需要什么语法才能正确存根的想法?



class Foo {
    constructor() {
        this.bar = new Bar();
    }

    omg() {
        this.bar.omg();
    }
}

class Bar {
    constructor() {
        console.log('In bar constructor');
    }

    omg() {
        console.log('In bar omg');
    }
}

const sandbox = sinon.createSandbox();
sandbox.stub(Bar.prototype, 'constructor');
sandbox.stub(Bar.prototype, 'omg');

describe('Foo', () => {
    describe('Constructor', () => {
        it('Should instantiate bar', () => {
            const foo = new Foo();
            expect(Bar.prototype.constructor.called).to.be.true;
        });
    });

    describe('Omg', () => {
        it("Should call Bar's omg method', () => {
            const foo = new Foo();
            foo.omg();
            expect(Bar.prototype.omg.called).to.be.true;
        });
    });
});




1 个答案:

答案 0 :(得分:0)

已经2年多了,这意味着很难。 :)

当很难做到时,则需要重构代码。

下面的示例可行,但可能无法在现实世界中使用(需要在定义Foo之前​​将Bar定义为存根)。

要点:

  • 使用stub calledWithNew()来检查Bar是否使用新的来调用。
  • 不使用arrow functions
  • 使用柴expect instanceof,因为Foo构造函数将添加属性 bar ,然后可以添加其他期望以检查属性bar,这意味着检查Foo的构造函数是否运行。
// @file stackoverflow.js
const sinon = require('sinon');
const { expect } = require('chai');

const sandbox = sinon.createSandbox();

// Define Bar as a stub.
const Bar = sandbox.stub();
const BarOmgFn = sinon.fake();
Bar.prototype.omg = BarOmgFn;

// class Bar {
//   constructor() {
//     console.log('In bar constructor');
//   }
//   omg() {
//     console.log('In bar omg');
//   }
// }

class Foo {
  constructor() {
    this.bar = new Bar();
  }

  omg() {
    this.bar.omg();
  }
}

describe('Foo', function () {
  after(function () {
    sandbox.restore();
  });
  describe('Constructor', function () {
    it('Should instantiate bar', function () {
      const foo = new Foo();

      // Check whether Bar called with new.
      expect(Bar.calledWithNew()).to.equal(true);
      // Check bar property.
      expect(foo.bar).to.be.instanceOf(Bar);
    });
  });

  describe('Omg', () => {
    it("Should call Bar's omg method", function () {
      const foo = new Foo();
      foo.omg();

      expect(BarOmgFn.calledOnce).to.equal(true);
    });
  });
});

使用mocha运行示例:

$ npx mocha stackoverflow.js


  Foo
    Constructor
      ✓ Should instantiate bar
    Omg
      ✓ Should call Bar's omg method


  2 passing (14ms)

$

从设计模式的角度来看,Foo类高度依赖于Bar类。重构可以使用dependency injection pattern。例如:对Foo类的简单更改,需要1个参数,它是Bar本身或Bar的实例。这项更改使代码更易于测试。

class Foo {
  // Now constructor need 1 argument
  constructor(Bar) {
    this.bar = new Bar();
  }

  omg() {
    this.bar.omg();
  }
}

希望这会有所帮助。