模拟es6合作者的建设

时间:2016-12-16 18:03:18

标签: javascript node.js mocking ecmascript-6 sinon

我有一个利用辅助类的类,我想验证它是否正确构造了这些对象。所以,我正在尝试在我的类中存根“构造函数”方法,但我显然没有做到这一点:

"use strict";

class Collaborator {
  constructor(settings) {
    console.log("Don't want this to be called!")
    this.settings = settings;
  }
}

class ThingToTest {
  constructor(settings) {
    this.helper = new Collaborator(settings);
  }
}

const assert = require("assert");
const sinon = require("sinon");

describe("ThingToTest", () => {
  let settings = "all the things"

  context("spying on constructor", () => {
    let spy = sinon.spy(Collaborator, "constructor")
    after(() => spy.restore()) 
    describe("constructor", () => {
      it("creates a Collaborator with provided settings", () => {
        new ThingToTest(settings);
        sinon.assert.calledWith(spy, settings)
      })
    })
  })

  context("spying on prototype constructor", () => {
    let spy = sinon.spy(Collaborator.prototype, "constructor")
    after(() => spy.restore()) 
    describe("constructor", () => {
      it("creates a Collaborator with provided settings", () => {
        new ThingToTest(settings);
        sinon.assert.calledWith(spy, settings)
      })
    })
  })

  context("stub constructor", () => {
    before(() => {
      sinon.stub(Collaborator, "constructor", (settings) => {
        console.log("This should be called so we can inspect", settings);
      })
    })
    after(() => { Collaborator.constructor.restore() }) 
    describe("constructor", () => {
      it("creates a Collaborator with provided settings", () => {
        new ThingToTest(settings);
      })
    })
  })

  context("stub prototype constructor", () => {
    before(() => {
      sinon.stub(Collaborator.prototype, "constructor", (settings) => {
        console.log("This should be called so we can inspect", settings);
      })
    })
    after(() => { Collaborator.prototype.constructor.restore() }) 
    describe("constructor", () => {
      it("creates a Collaborator with provided settings", () => {
        new ThingToTest(settings);
      })
    })
  })

})

运行它会产生这些(不合需要的)结果:

ThingToTest
    spying on constructor
      constructor
Don't want this to be called!
        1) creates a Collaborator with provided settings
    spying on prototype constructor
      constructor
Don't want this to be called!
        2) creates a Collaborator with provided settings
    stub constructor
      constructor
Don't want this to be called!
        ✓ creates a Collaborator with provided settings
    stub prototype constructor
      constructor
Don't want this to be called!
        ✓ creates a Collaborator with provided settings

似乎存根是有点工作,因为在间谍测试错误之前将存根测试与可怕的“TypeError:尝试包装已经包装的构造函数”。因此,清楚地弄清楚如何模拟Collaborators构造函数只是我做错的一半。 。 。我也没有正确恢复构造函数。有什么建议吗?

2 个答案:

答案 0 :(得分:0)

这是不是我想要的解决方案,但是暂时我可能最终会使用这个(但是,如果你有建议,请告诉我自己):

context("checking Collaborator in a more integration style test", () => {
    describe("constructor", () => {
      it("creates a Collaborator with provided settings", () => {
        let thing = new ThingToTest(settings);
        assert.equal(thing.helper.settings, settings)
      })
    })
  })

这会传递并验证Collaborator是否设置了正确的设置。但是现在如果我想重构Collaborator构造函数,我将打破ThingToTest。再一次,我仍然希望有人可以建议一种方法来实际测试这门课程!

答案 1 :(得分:0)

不确定这是我的最终答案,但我最终使用了proxyquire,因为它是我迄今为止找到的最佳解决方案。为了说明它是如何工作的,我将测试中的类分成了自己的目录,并将测试文件分成了一个子项" test"目录。这说明了如何在proxyquire工作中的路径(这花了我一些时间来弄清楚)。所以,这就是我最终的结果:

/Collaborator.js

"use strict"

class Collaborator {
  constructor(settings) {
    console.log("Don't want this to be called!")
    this.settings = settings;
  }
}

module.exports = Collaborator

/ThingToTest.js

"use strict"

const Collaborator = require("./Collaborator")

class ThingToTest {
  constructor(settings) {
    this.helper = new Collaborator(settings)
  }
}

module.exports = ThingToTest

/test/ExampleTest.js

"use strict";

const proxyquire = require('proxyquire')
const mockCollaborator = sinon.stub();
const ThingToTest = proxyquire("../ThingToTest", { "./Collaborator" : mockCollaborator })

const assert = require("assert");
const sinon = require("sinon");

describe("ThingToTest", () => {
  let settings = "all the things"

  context("checking Collaborator in a more integration style test", () => {

    describe("constructor", () => {
      it("creates a Collaborator with provided settings", () => {
        let thing = new ThingToTest(settings);
        assert.equal(mockCollab.firstCall.calledWith(settings))
      })
    })
  })
})

请注意proxyquire("../ThingToTest", { "./Collaborator" : mockCollaborator })内的路径如何匹配" ThingToTest"使用,来自测试类的路径。我希望这有助于其他人,但我仍然愿意接受其他想法和建议!