Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mock angularjs service for unit testing using jasmine

I have an Angular App and I want to create unit test cases for it using jasmine.
In my AngularJS app, I have a service as :

var canceler;
var myServices = angular.module('myServices', ['ngResource'])

myServices.factory('getData', ['$http', '$q', function($http, $q){
    var canceler;
    return {
        setData: function(url, callback, error) {
                    canceler = $q.defer();
                    $http.post(url, {}, {timeout:canceler.promise}).success(callback).error(error);
        },
        abort: function(){ canceler.resolve();}
    }
}]);

This service is being used by controller.

Now how can I provide a mock for this "getData" service to the injector I am using in controllerSpecs.js (for the unit testing using jasmine).

For the reference, the code of controllerSpecs.js is defined in Getting error while using Jasmine with AngularJS.

like image 976
r.bhardwaj Avatar asked Jan 22 '14 07:01

r.bhardwaj


People also ask

What is Jasmine testing framework and how do you use it for Angular unit testing?

Jasmine is a behavior development testing framework. Unit tests are written using Jasmine and are run to see if individual parts of an application are working correctly. As a result, unit tests will either pass or fail depending on if the code is working correctly or has a bug.

Is AngularJS code unit testable?

AngularJS is written with testability in mind, but it still requires that you do the right thing. We tried to make the right thing easy, but if you ignore these guidelines you may end up with an untestable application.


2 Answers

You can use AngularJS's $provide service. This page demonstrates how to mock the functionality of a service using Jasmine's spies. Basically in your Jasmine test you can include:

var getDataMock;

beforeEach(function() {
  getDataMock = {
    setData: jasmine.createSpy(), 
    abort: jasmine.createSpy()
  };

  module(function($provide) {
    $provide.value('getData', getDataMock);
  });
});

This tells AngularJS that instead of using the real getData service, the mock will be used in its place. In this example, using a Jasmine spy for the mock lets you easily create expectations about how and when the getData service is called by the controller. You can alternatively set getDataMock to any other object, though it makes sense to support the same API as the real getData service.

For bonus points, you can specify the getDataMock object in a separate file, so that the mock may be easily used in any number of unit tests where the thing being tested uses getData. This however requires some configuration with whatever Jasmine runner you are using.

This is all assuming you wish to unit test the controller. If you want to unit test the getData service itself, AngularJS provides a nice mocking utility specifically for http requests.

like image 119
jelinson Avatar answered Nov 29 '22 19:11

jelinson


Try something like this

//creation mock service
var mockGetData = {
  data: [],
  setData: function(url, callback, error){
    //emulate real work, any logic can be here
    data.push('called');
    callback(data);
  }
}

and use of the mock service

it('test description', inject(function ($rootScope, $controller){
  var scope = $rootScope.$new();
  var ctrl = $controller('TodoController', { $scope: scope, getData: mockGetData });
  //some test here....
}))
like image 44
IgorCh Avatar answered Nov 29 '22 18:11

IgorCh