Jasmine: createSpy() and createSpyObj()
Jasmine's createSpy()
method is useful when you do not have any function to spy upon or when the call to the original function would inflict a lag in time (especially if it involves HTTP requests) or has other dependencies which may not be available in the current context.
Like spyOn()
, it also tracks calls and arguments, but without any real implementation. But unlike spyOn()
, the method to be spied upon need not exist at all.

createSpy()
takes two parameters, both of which are optional:
jasmine.createSpy(name, originalFunction)
name
originalFunction
Now consider the constructor function Bird()
below. The constructor has a method called getSound()
which returns the text 'Chirp, Chirp!'
.
function Bird() {
this.getSound = function() {
return 'Chirp, Chirp!';
}
};
createSpy()
We create an instance of Bird()
, which is b
. This instance inherits the getSound()
method from the constructor, but we have replaced it with a spy returning fake method using jasmine.createSpy()
below.
describe("Testing Bird with fake getSound() method", function() {
it('calls the fake getSound() method created by createSpy()', function() {
var b = new Bird();
b.getSound = jasmine.createSpy();
b.getSound();
expect(b.getSound).toHaveBeenCalled();
});
});
The above spec passes.

However, it is always a good practice to pass at least the method name to createSpy()
so as to identify the function if some errors toss up while running the spec. Else, messages as the following would get printed in the terminal.
'undefined' is not a function (evaluating 'jasmine.createSpy() ...
The toHaveBeenCalled()
matcher used above may not have been that transparent, in the sense that it might have left you wondering whether it was the real method belonging to the constructor that got invoked or the fake one returned by createSpy()
. So let us clear things up by returning some specific values we can distinguish. We make use of the and.returnValue()
method for the purpose. The return text is changed to 'Tweet, Tweet!'
.
The console.log()
statement was actually quite unnecessary, but it was just to bring to notice in your terminal that the original "Chirp, Chirp!" has really been replaced with the value returned by a fakie. Note that getSound()
is invoked inside the expect()
function; it is getSound()
and not getSound
.
describe("Testing Bird with fake getSound() method", function() {
it('calls the fake getSound() created by createSpy() with return value', function() {
var b = new Bird();
b.getSound = jasmine.createSpy().and.returnValue('Tweet, Tweet!');
console.log(b.getSound());
expect(b.getSound()).toEqual('Tweet, Tweet!');
});
});

Actually, the entire function can be replicated using callFake()
.
describe("Testing Bird with fake getSound() method", function() {
it('calls the fake getSound() method created by createSpy()', function() {
var b = new Bird();
b.getSound = jasmine.createSpy().and.callFake(function(){
return 'Hoot, Hoot!';
});
console.log(b.getSound());
expect(b.getSound()).toEqual('Hoot, Hoot!');
});
});

createSpyObj()
The createSpyObj()
creates a mock object with multiple spies. The created object has the spy methods as its properties, with their respective return values as its values. The syntax is as follows:
jasmine.createSpyObj(baseName, methodNames)
baseName
methodNames
We can forget our usual example constructor function here for the time being as all spy methods below are created out of nothing.

describe("Multiple spies created with createSpyObj()", function() {
var ball;
beforeEach(function() {
ball = jasmine.createSpyObj('ball', ['roll', 'bounce', 'stop']);
});
it('should create multiple spy methods', function() {
expect(ball.roll).toBeDefined();
expect(ball.bounce).toBeDefined();
expect(ball.stop).toBeDefined();
});
});

Next we check if they have been invoked, with the toHaveBeenCalled()
matcher.
describe("Multiple spies created with createSpyObj()", function() {
var ball;
beforeEach(function() {
ball = jasmine.createSpyObj('ball', ['roll', 'bounce', 'stop']);
ball.roll();
ball.bounce(4);
ball.stop();
});
it('should track the invoked spy methods', function() {
expect(ball.roll).toHaveBeenCalled();
expect(ball.bounce).toHaveBeenCalled();
expect(ball.stop).toHaveBeenCalled();
});
});