【问题标题】:Spying on a constructor using Jasmine使用 Jasmine 监视构造函数
【发布时间】:2012-03-09 23:55:26
【问题描述】:

我正在使用 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() 方法不存在”错误。我这样做对吗?谢谢!

【问题讨论】:

  • 你想“窥探”它的原因是什么?
  • 我想确保创建了翻转计数器并设置了正确的值。

标签: javascript jasmine spy


【解决方案1】:

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

spyOn(flipCounter.prototype, 'setValue').and.callThrough();
var myFlipCounter = new flipCounter("counter", {inc: 23, pace: 500});
expect(flipCounter.prototype.setValue).toHaveBeenCalledTimes(1);

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

  • 我更喜欢这个答案而不是 @ggozad 的答案,因为它使外部模块与测试隔离,并使用专门为模拟类实例对象而设计的内置 jasmine 实用程序。
【解决方案3】:

您必须为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);
  });
});

【讨论】:

    【解决方案4】:

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

    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});
    

    【讨论】:

      【解决方案5】:

      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);
      

      【讨论】:

      • 在任何情况下当你做 spyOn(window, 'flipCounter').andReturn(myStub);你已经用什么都不做的东西替换了你的构造函数。您必须在测试时调用或复制构造函数。
      • Jasmine 2.0 中的语法是 spyOn(foo, 'getBar').and.callThrough();
      • 如果你是在服务器端运行这段代码,并且没有窗口,你可以用什么来指代调用new flipCounter()的环境?
      • 嗯 - 这不太合理。它底部的例子很奇怪。我当然想创建间谍来将其注入其他代码 - 即,将构建某些东西的代码得到一个间谍,这样你就可以操纵它在测试中的行为。
      【解决方案6】:

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

      来自文档:

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

      模拟(和模拟期望)是虚假的方法(如间谍) 预编程的行为(如存根)以及预编程的 期望。如果未将模拟用作 预计。

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

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

      【讨论】:

      • 当 Jasmine 内置了强大的模拟功能时,无需使用额外的库。Sinon.js 对其他事情很有用
      猜你喜欢
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 2017-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多