spyOn() & jasmine.createSpyObj()

spyOn()

Jasmine has test double functions called spies. A spy can stub any function and tracks calls to it and all arguments. A spy only exists in the describe or it block in which it is defined, and will be removed after each spec. There are special matchers for interacting with spies. This syntax has changed for Jasmine 2.0. The toHaveBeenCalled matcher will return true if the spy was called. The toHaveBeenCalledWith matcher will return true if the argument list matches any of the recorded calls to the spy.

In our component we have the following method:

add(n1: number, n2: number) {
    this.logger.log("Addition operation called");
    return n1 + n2;
}

And our spec code we will run the following the code to verify if the this.logger.log is being called only once.

it('should add two numbers', () => {
    const logger = new LoggerService(); // Here we create a new instance of logger service
    spyOn(logger, 'log');
    const calculator = new CalculatorService(logger);
    const result = calculator.add(2, 2);
    expect(result).toBe(4); // First exepct
    
    // Validate how many times the logger is being called
    expect(logger.log).toHaveBeenCalledTimes(1); // Check if the function is being called only once
});

However, if we modify our code to make it fail we can double call the method.

this.logger.log("Addition operation called");
this.logger.log("Addition operation called 2cd");

And here is the result of calling twice the same function:

jasmine.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.

it('should add two numbers', () => {
    // Implementing Jasmine Create Spy Object
    const logger = jasmine.createSpyObj('LoggerService', ['log']);
    
    const calculator = new CalculatorService(logger);
    const result = calculator.add(2, 2);
    expect(result).toBe(4); // First exepct
    
    // Validate how many times the logger is being called
    // Check if the function is being called only once
    expect(logger.log).toHaveBeenCalledTimes(1);
});

When there is not a function to spy on, jasmine.createSpy can create a "bare" spy. This spy acts as any other spy - tracking calls, arguments, etc. But there is no implementation behind it. Spies are JavaScript objects and can be used as such.

What's the difference between spyOn and jasmine.createSpyObj

The difference is that you should have a method on the object with spyOn

const o = { some(): { console.log('spied') } };
spyOn(o, 'some');

while the mock method is created for your with createSpy():

const o = {};
o.some = jasmine.createSpy('some');

The advantage of the spyOn is that you can call the original method

spyOn(o, 'some').and.callThrough();
o.some(); // logs 'spied'

Last updated