71

我正在使用 Jasmine 测试是否创建了某些对象并在它们上调用了方法。

我有一个 jQuery 小部件,它创建翻转计数器对象并在它们上调用 setValue 方法。翻转计数器的代码在这里:https ://bitbucket.org/cnanney/apple-style-flip-counter/src/13fd00129a41/js/flipcounter.js

翻转计数器是使用以下方法创建的:

var myFlipCounter = new flipCounter("counter", {inc: 23, pace: 500});

我想测试是否创建了翻转计数器并在它们上调用了 setValue 方法。我的问题是我如何在这些对象被创建之前监视它们?我是否监视构造函数并返回假对象?示例代码真的很有帮助。谢谢你的帮助!:)

更新:

我试过像这样监视flipCounter:

myStub = jasmine.createSpy('myStub');
spyOn(window, 'flipCounter').andReturn(myStub);

//expectation
expect(window.flipCounter).toHaveBeenCalled();

然后通过 flipCounter 测试 setValue 调用:

spyOn(myStub, 'setValue');

//expectation
expect(myStub.setValue).toHaveBeenCalled();

初始化 FlipCounter 的第一个测试很好,但是对于测试 setValue 调用,我得到的只是“setValue() 方法不存在”错误。我这样做对吗?谢谢!

4

6 回答 6

50

flipCounter只是另一个函数,即使它也恰好构造了一个对象。因此你可以这样做:

var cSpy = spyOn(window, 'flipCounter');

得到一个间谍,并对它进行各种检查,或者说:

var cSpy = spyOn(window, 'flipCounter').andCallThrough();
var counter = flipCounter('foo', options);
expect(cSpy).wasCalled();

然而,这似乎有些矫枉过正。这样做就足够了:

var myFlipCounter = new flipCounter("counter", options);
expect(myFlipCounter).toBeDefined();
expect(myFlipCounter.getValue(foo)).toEqual(bar);
于 2012-02-19T09:26:38.610 回答
15

我建议jasmine.createSpyObj()在您想模拟具有需要监视的属性的对象时使用。

myStub = jasmine.createSpyObj('myStub', ['setValue']);
spyOn(window, 'flipCounter').andReturn(myStub);

这会测试与预期flipCounter接口的交互,而不依赖于flipCounter实现。

于 2016-06-09T20:26:35.847 回答
5

以下不依赖于“窗口”。假设这是您要测试的代码 -

function startCountingFlips(flipCounter) {
    var myFlipCounter = new flipCounter("counter", {inc: 23, pace: 500});
}

你的测试可能是 -

var initSpy = jasmine.createSpy('initFlipCounter');
var flipCounter = function(id, options) {
    initSpy(id, options);
}
startCountingFlips(flipCounter);
expect(initSpy).toHaveBeenCalledWith("counter", {inc:23, pace:500});
于 2014-06-05T15:33:29.210 回答
4

您必须实现一个假构造函数flipCounter,将setValue属性设置为一个间谍函数。假设您要测试的功能是这样的:

function flipIt() {
  var myFlipCounter = new flipCounter("counter", {inc: 23, pace: 500});
  myFlipCounter.setValue(100);
}

您的规格应如下所示:

describe('flipIt', function () {
  var setValue;
  beforeEach(function () {
    setValue = jasmine.createSpy('setValue');
    spyOn(window, 'flipCounter').and.callFake(function () {
      this.setValue = setValue;
    });
    flipIt();
  });
  it('should call flipCounter constructor', function () {
    expect(window.flipCounter)
      .toHaveBeenCalledWith("counter", {inc: 23, pace: 500});
  });
  it('should call flipCounter.setValue', function () {
    expect(setValue).toHaveBeenCalledWith(100);
  });
});
于 2015-10-20T13:48:42.497 回答
3

我测试构造函数的版本是监视原型:

spyOn(flipCounter.prototype, 'setValue').and.callThrough();
var myFlipCounter = new flipCounter("counter", {inc: 23, pace: 500});
expect(flipCounter.prototype.setValue).toHaveBeenCalledTimes(1);
于 2017-09-20T08:35:38.383 回答
-4

不知道如何使用 jasmine 模拟来做到这一点,但如果你想要强大的模拟/间谍/存根,我推荐sinon.js,它与 jasmine 配合得很好。

来自文档:

测试间谍是一个函数,它记录所有调用的参数、返回值、this 的值和抛出的异常(如果有的话)。测试间谍可以是匿名函数,也可以包装现有函数。

模拟(和模拟期望)是具有预编程行为(如存根)和预编程期望的虚假方法(如间谍)。如果没有按预期使用模拟,它将无法通过您的测试。

使用 sinon.js,您可以创建一个返回另一个间谍的 FlipCounter 构造函数的模拟。

然后断言构造函数是使用constructorMock.calledWithNew()调用的,并断言返回的spy是使用returnSpy.calledWith(arg1, arg2...)调用的。

于 2012-02-19T09:02:28.273 回答