55

我正在努力弄清楚如何使用 sinon 来模拟构造函数。我有一个函数,它将通过调用一个接受一些参数的构造函数来创建多个小部件。我想验证构造函数是否使用正确的参数被调用了正确的次数,但我不想实际构造小部件。以下链接似乎解释了一种模拟构造函数的简单方法,但它对我不起作用:

使用 Jasmine 监视构造函数

http://tinnedfruit.com/2011/03/25/testing-backbone-apps-with-jasmine-sinon-2.html

当我对构造函数进行以下调用时:

sinon.stub(window, "MyWidget");

我收到以下错误:

Uncaught TypeError: Attempted to wrap undefined property MyWidget as function 

在 Chrome 中调试时,我看到 MyWidget 出现在 Scope Variables 的 Local 部分中,但是窗口中没有 MyWidget 属性。

任何帮助将不胜感激。

4

9 回答 9

24

我需要一个解决方案,因为我的代码正在调用 new 运算符。我想模拟新调用创建的对象。

var MockExample = sinon.stub();
MockExample.prototype.test = sinon.stub().returns("42");
var example = new MockExample();
console.log("example: " + example.test()); // outputs 42

然后我使用 rewire 将其注入到我正在测试的代码中

rewiredModule = rewire('/path/to/module.js');
rewiredModule.__set__("Example", example);
于 2015-11-19T16:48:31.210 回答
8

来自 sinonjs 的官方网站:

用存根函数替换 object.method。调用object.method.restore()可以恢复原来的函数;(或 stub.restore();)。如果属性不是>已经是函数,则会引发异常,以帮助避免在存根方法时出现拼写错误。

这只是说明您要为其创建存根的函数必须是对象对象的成员。

把事情说清楚;你打电话

sinon.stub(window, "MyWidget");

MyWidget 函数需要在全局范围内(因为您将window作为参数传递)。但是,正如您已经说过的,此函数位于本地范围内(可能在对象文字或命名空间中定义)。

在 javascript 中,每个人都可以访问全局范围,但反之则不行。

检查您在哪里声明 MyWidget 函数并将容器对象作为第一个参数传递给 sinon.stub()

于 2013-01-28T21:12:46.363 回答
6

使用 Sinon 4.4.2,我能够模拟这样的实例方法:

const testObj = { /* any object */ }
sinon.stub(MyClass.prototype, "myMethod").resolves(testObj)
let myVar = await new MyClass(token).myMethod(arg1, arg2)
// myVar === testObj

这里提供了一个类似的解决方案: Stubbing a class method with Sinon.js

于 2018-07-12T22:26:55.073 回答
2

我使用 Mockery 来模拟构造函数/函数,没有任何问题。

var mockery = require('mockery');
var sinon = require('sinon');

mockery.enable({
  useCleanCache: true,
  warnOnReplace: false,
  warnOnUnregistered: false
});

exports.Client = function() {/* Client constructor Mock */};
var ClientSpy = sinon.spy(exports, 'Client');
mockery.registerMock('Client', ClientSpy);

var Factory = require('Factory'); // this module requires the Client module

您应该能够像上面的示例一样应用 Sinon Spy。

确保在测试后禁用或重置 Mockery!

于 2015-04-17T17:39:02.807 回答
2

使用sinon.createStubInstance(MyES6ClassName),则当使用new关键字调用 MyES6ClassName 时,将返回 MyES6ClassName 实例的存根。

于 2019-06-11T09:36:20.907 回答
0

刚刚在文档中找到了这个。

如果要创建 MyConstructor 的存根对象,但不希望调用构造函数,请使用此实用程序函数。

var stub = sinon.createStubInstance(MyConstructor)

于 2015-06-04T14:18:36.640 回答
0

我通过错误输入sinon.stub.throws(expectedErr)而不是sinon.stub().throws(expectedErr). 我以前犯过类似的错误,以前没有遇到过这个特定的消息,所以它把我扔了。

于 2017-02-12T00:52:06.897 回答
0

用 sinon 模拟和存根构造函数

我给出两个解决方案。第一个解决了这个问题,如何用行为来模拟构造函数,第二个展示了如何用一个假人来存根它。谷歌多次引导我回答这个问题,以搜索如何存根。

用行为模拟构造函数

我不知道这是否是最短路径。至少它确实如此,所要求的。

首先,我使用 sinon 的fake方法来创建一个Mock具有我想要的行为的模拟构造函数。然后我必须一一添加方法。由于我没有调查的原因,在将整个原型设置为UnderTestto时它不起作用Mock

require('chai').should();
const { fake} = require('sinon');

class UnderTest {
  constructor() {
    this.mocked = false;
  }

  isMocked() {
    return this.mocked;
  }
}

describe('UnderTest', () => {
  let underTest;
  let isMocked;
  before(() => {
    const Mock = fake(function () { this.mocked = true; });
    Mock.prototype.isMocked = UnderTest.prototype.isMocked;
    underTest = new Mock();
    isMocked = underTest.isMocked();
  });
  it('should be mocked', () => {
    isMocked.should.be.true;
  });
});

用假人存根构造函数

如果你被引导到这篇文章,因为你只想存根构造函数以防止它被执行。

SinoncreateStubInstance创建了一个存根构造函数。它还存根所有方法。因此,被测方法必须先恢复。

require('chai').should();
const { createStubInstance } = require('sinon');

class UnderTest {
  constructor() {
    throw new Error('must not be called');
  }

  testThis() {
    this.stubThis();
    return true;
  }

  stubThis() {
    throw new Error('must not be called');
  }
}

describe('UnderTest', () => {
  describe('.testThis()', () => {
    describe('when not stubbed', () => {
      let underTest;
      let result;
      before(() => {
        underTest = createStubInstance(UnderTest);
        underTest.testThis.restore();
        result = underTest.testThis();
      });
      it('should return true', () => {
        result.should.be.true;
      });
      it('should call stubThis()', () => {
        underTest.stubThis.calledOnce.should.be.true;
      });
    });
  });
});
于 2021-12-25T14:49:22.343 回答
-19

经过一些调整后,我能够让StubModule工作,最值得注意的是在存根模块中需要时将 async:false 作为配置的一部分传递。

感谢戴维斯先生把这些放在一起

于 2013-06-13T20:41:44.343 回答