Testing Services and AJAX

Services are one of the most common components in an AngularJS application. They provide a way to define re-usable logic in a central place so that one doesn’t need to repeat the same logic over and over. The singleton nature of the service makes it possible to share the same piece of data across multiple controllers, directives and even other services.

A service can depend on a set of other services to perform its task. Say, a service named A depends on the services B, C and D to perform its task. While testing the service A, the dependencies B, C and D have to be replaced with mocks.

We generally mock all the dependencies, except certain utility services like $rootScope and $parse. We create spies on the methods that have to be inspected in the tests (in Jasmine, mocks are referred to as spies) using jasmine.createSpy() which will return a brand new function.

Let’s consider the following service:

angular.module(‘services’, [])

.service(‘sampleSvc’, [‘$window’, ‘modalSvc’, function($window, modalSvc){

this.showDialog = function(message, title){

if(title){

modalSvc.showModalDialog({

title: title,

message: message

});

} else {

$window.alert(message);

}

};

}]);

This service has just one method (showDialog). Depending on the value of the input this method receives, it calls one of two services that are injected into it as dependencies ($window or modalSvc).

To test sampleSvc we need to mock both of the dependent services, load the angular module that contains our service and get references to all the objects:

var mockWindow, mockModalSvc, sampleSvcObj;

beforeEach(function(){

module(function($provide){

$provide.service(‘$window’, function(){

this.alert= jasmine.createSpy(‘alert’);

});

$provide.service(‘modalSvc’, function(){

this.showModalDialog = jasmine.createSpy(‘showModalDialog’);

});

});

module(‘services’);

});

beforeEach(inject(function($window, modalSvc, sampleSvc){

mockWindow=$window;

mockModalSvc=modalSvc;

sampleSvcObj=sampleSvc;

}));

Now we can test the behavior of the showDialog method. The two test cases we can write for the method are as follows:

  • it calls alert if no title is parameter is passed in
  • it calls showModalDialog if both title and message parameters are present

The following snippet shows these tests:

it(‘should show alert when title is not passed into showDialog’, function(){

var message=”Some message”;

sampleSvcObj.showDialog(message);

expect(mockWindow.alert).toHaveBeenCalledWith(message);

expect(mockModalSvc.showModalDialog).not.toHaveBeenCalled();

});

it(‘should show modal when title is passed into showDialog’, function(){

var message=”Some message”;

var title=”Some title”;

sampleSvcObj.showDialog(message, title);

expect(mockModalSvc.showModalDialog).toHaveBeenCalledWith({

message: message,

title: title

});

expect(mockWindow.alert).not.toHaveBeenCalled();

});

This method doesn’t have a lot of logic to test, whereas the services in typical web apps would normally contain a lot of functionality. You can use the technique demonstrated in this tip for mocking and getting the references to services. The service tests should cover every possible scenario that was assumed while writing the service.

Factories and values can also be tested using the same technique.

Share this post
[social_warfare]
Controller Testing
Testing Filters

Get industry recognized certification – Contact us

keyboard_arrow_up