jasmine

Spies

Remarks#

A spy is defined as a test specific function which intercepts calls to an underlying function in the application code and dispatches its own implementation when the underlying function is called to test the interface rather than the implementation.

Spying on an existing function

Jasmine can spy on an existing function using the spyOn function.

let calculator = {
  multiply: function(a, b) {
     return a * b;
  },

  square: function(a) {
    return this.multiply(a, a);
  }
}


describe('calculator', function() {
  it('squares numbers by multiplying them by themselves', function() {
    let num = 2;
    spyOn(calculator, 'multiply');
    calculator.square(NUM);
    expect(calculator.multiply).toHaveBeenCalledWith(NUM, NUM);
  })
});

After the function has been spied on it is replaced with a spy, that can be queried for information about how and when it has been called.

Creating a new spy

We can use jasmine.createSpy() to create a standalone spy. This is often useful if we need to pass a function as a callback to another function and want to test how it is used.

// source code
function each(arr, fn) {
    arr.forEach(fn);
}

// test code
describe('each', function() {
  let mockFn = jasmine.createSpy();

  it('calls a function for each item in the array ', function() {
    let arr = [1,2,3,4,5]
    each(arr, mockFn);
    expect(mockFn.calls.count()).toBe(arr.length);
  })
});

Spying on an angular service

In this example we have a service, let’s call it search service that has a method called search() which will initiate a get request to a back end API.

function SearchService($http) {
    const service = {};
    
    service.search = function() {
        return $http({method: 'GET', url: `/api/search`})
    }        

    return service;
}
angular.module('app').factory('searchService', SearchService);

Testing

describe('search service', function() {
    var $httpBackend;
    var searchService;
    beforeEach(angular.mock.module('app'));
    
    beforeEach(inject(function(_$httpBackend_, _searchService_) {
        $httpBackend = _$httpBackend_;            
        searchService = _searchService_;
    }));

    it('should perform http call to the search api', function(){
        searchService.search();
        $httpBackend.expectGET('/api/search');
    });

})

Spying on an angular service that doesn’t call back end service

function calculatorService() {
    const service = {};
    service.add = function(a,b) {
        return a + b
    }        

    return service;
}

angular.module('app').factory('calculatorService', calculatorService);

Testing

describe('calculator service', function() {
    var calculatorService;
    beforeEach(angular.mock.module('app'));
    
    beforeEach(inject(function(_calculatorService_) {
         calculatorService = _calculatorService_;
    }));

    it('should should add two numbers', function(){
        var actual = calculatorService.add(1,2);
        expect(actual).toBe(3);
    });
})

Spying on a property

const foop = {
    get value() {},
    set value(v) {}
};

it('can spy on getter', () => {
    spyOnProperty(foop, 'value', 'get').and.returnValue(1);
    expect(foop.value).toBe(1);
});

it('and on setters', () => {
    const spiez = spyOnProperty(foop, 'value', 'set');
    foop.value = true;
    expect(spiez).toHaveBeenCalled();
});

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow