Spying on a constructor using Jasmine

浪子不回头ぞ 提交于 2019-12-17 16:43:06

问题


I am using Jasmine to test if certain objects are created and methods are called on them.

I have a jQuery widget that creates flipcounter objects and calls the setValue method on them. The code for flipcounter is here: https://bitbucket.org/cnanney/apple-style-flip-counter/src/13fd00129a41/js/flipcounter.js

The flipcounters are created using:

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

I want to test that the flipcounters are created and the setValue method is called on them. My problem is that how do I spy on these objects even before they are created? Do I spy on the constructor and return fake objects? Sample code would really help. Thanks for your help! :)

Update:

I've tried spying on the flipCounter like this:

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

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

Then testing for the setValue call by flipCounter:

spyOn(myStub, 'setValue');

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

the first test for initializing flipCounter is fine, but for testing the setValue call, all I'm getting is a 'setValue() method does not exist' error. Am I doing this the right way? Thanks!


回答1:


flipCounter is just another function, even if it also happens to construct an object. Hence you can do:

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

to obtain a spy on it, and do all sorts of inspections on it or say:

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

However, this seems overkill. It would be enough to do:

var myFlipCounter = new flipCounter("counter", options);
expect(myFlipCounter).toBeDefined();
expect(myFlipCounter.getValue(foo)).toEqual(bar);



回答2:


I would suggest using jasmine.createSpyObj() when you want to mock objects with properties that need to be spied on.

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

This tests interactions with the expected flipCounter interface, without depending on the flipCounter implementation.




回答3:


The following does not rely on 'window'. Lets say this is the code you want to test -

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

Your test could be -

var initSpy = jasmine.createSpy('initFlipCounter');
var flipCounter = function(id, options) {
    initSpy(id, options);
}
startCountingFlips(flipCounter);
expect(initSpy).toHaveBeenCalledWith("counter", {inc:23, pace:500});



回答4:


You have to implement a fake constructor for flipCounter that sets the setValue property to a spy function. Let's say the function you want to test is this:

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

Your spec should look like this:

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



回答5:


My version to test a constructor is to spy on the prototype:

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



回答6:


Don't know how to do this using jasmine mocks, but if you want powerful mocking/spy/stubs I recommend sinon.js, wich works very well with jasmine.

From docs:

A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls. A test spy can be an anonymous function or it can wrap an existing function.

Mocks (and mock expectations) are fake methods (like spies) with pre-programmed behavior (like stubs) as well as pre-programmed expectations. A mock will fail your test if it is not used as expected.

With sinon.js you could create a mock of the flipCounter constructor that returns another spy.

Then assert that the constructor was called using constructorMock.calledWithNew(), and assert that the returned spy was called with returnedSpy.calledWith(arg1, arg2...).



来源:https://stackoverflow.com/questions/9347631/spying-on-a-constructor-using-jasmine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!