DotNetCurry Logo

Unit Testing an Angular.js Service using Jasmine and Karma

Posted by: Mahesh Sabnis , on 2/26/2016, in Category AngularJS
Views: 24857
Abstract: Using $httpBackEnd object in Angular.js for unit testing Angular services.

Since Angular.js facilitates separation of client-side components with the help of inbuilt dependency injection (DI) management, it has testing support for every component e.g. Angular Controller, Angular Service, etc. It’s an always good idea of testing client-side components before deployment.

 

We have already explored how to test Angular Controllers in a separate article http://www.dotnetcurry.com/angularjs/1248/unit-testing-angularjs-controllers-jasmine-karma. In this article we will test an Angular Service. Here are some frameworks which can be used for testing AngularJS applications.

  • Jasmine - is a behavior-driven development framework for testing JavaScript code. A major feature of this framework is that is does not depend on any JavaScript framework and neither it needs DOM to test the code. This provides for clean syntax using which we can write tests. Jasmine also provides functions for structuring the test using assertions. More information about Jasmine can be obtained from http://jasmine.github.io/2.4/introduction.html
  • Protractor - is an end-to-end testing framework for Angular.js applications. This framework runs tests against the application running in a real browser. This is a Node.js program and uses Jasmine for its test syntax. More information about Protractor can be read from https://angular.github.io/protractor/#/ and http://angular.github.io/protractor/#/api.
  • Karma - is a JavaScript command line tool. This tool is used to use the web server to load the application code and test it. This tool runs on Node.js and is available as a NPM package. More information about this tool can be read from http://karma-runner.github.io/0.13/index.html

We will be using Jasmine with Karma. We will also use the Free Community edition of Visual Studio 2015 for our sample although you can use any other IDE like Visual Studio Code etc.

Prerequisites: We must have Node.js already installed on our system.

Unit Testing Angular.js application

The application used in this article uses Web API to create a REST service. A sample Web API with Angular application can be downloaded from http://www.dotnetcurry.com/aspnet/1049/crud-database-aspnet-webapi-angularjs.

Step 1: Open Visual Studio and create an empty application. Name this application as ‘NG_TestServApp’. In this project, add a new NPM Configuration file (Package.json).

Step 2: Right-click on the project and using Manage NuGet Packages install AngularJS.Core package in the project. After installation of this package, the project will add Scripts folder with the following JavaScript files in it.

  • angular.js.
  • anguar.min.js.
  • angular-mocks.js

Angular mocks is an ngMock module. This provides mocking for our tests. This injects and mocks the angular service within the unit tests.

Step 3: Since we will be using Jasmine framework with Karma, we need to install their packages. Open the Node.js command prompt and navigate to the project created. Run the following commands from the command prompt:

npm install jasmine

This will install the jasmine framework and its samples in the scripts folder. Run the following command to install Karma, Karma jasmine core and chrome launcher.

npm install karma karma-jasmine karma-chrome-launcher --save-dev

Run the following command to install the karma-cli:

npm install karma-cli

We need to initialize Karma so that we can define which JavaScript files will be used for testing, or what JavaScript framework will be used or, which browser will be used, and so on. To define this initialization, run the following command from the command prompt

karma init

Running this command will ask you for the Testing Environment settings. The following needs to be selected

· Testing Framework: Jasmine

· Require.js: no

· Capture any browser automatically : chrome

  • o Press Enter twice

· Location of Source and test files: press enter

· Should any files included by the previous pattern to be excluded: press enter

· Do you want Karma to Watch all the files and run the tests on change: yes

These steps will generate karma.conf.js.

Note: By default this file will be hidden, click on show all file option of the Solution Explorer window in Visual Studio and include the file in the project by right clicking on the file.

Step 4: In the project, add a new folder of name MyScripts. In this folder add a JavaScript file with name app.js. Add the following JavaScript code in it.

app.js

var app = angular.module('mdl', []);
/// <reference path="mymodule.js" />
app.service('myserv', function ($http) {

    this.getData = function () {
        var result = $http.get("http://localhost:36337/api/EmployeeInfoAPI");
        return result; //deferrer
    };

    this.get = function (id) {
        var result = $http.get("http://localhost:36337/api/EmployeeInfoAPI/" + id);
        return result; //deferrer
    };

     
});

The above code defines angular module of name mdl. This module contains angular service of name myserv with getData() and get() functions. These functions call the Web API service using the URL. (Note: Please change above URLs with actual REST service created by you.)

 

Step 5: In the project, add a folder of name Test. In this folder, add a new JavaScript file of name Test.js. We will add the following code in it to test the angular service.

//1.
describe('myserv', function () {
    var myserv, httpBackend;
    //2.
    beforeEach(function () {
        //3. load the module.
        module('mdl');

        // 4. get your service, also get $httpBackend
        // $httpBackend will be a mock.
        inject(function ($httpBackend, _myserv_) {
            myserv = _myserv_;
            httpBackend = $httpBackend;
        });
    });

    // 5. make sure no expectations were missed in your tests.
    afterEach(function () {
        httpBackend.verifyNoOutstandingExpectation();
        httpBackend.verifyNoOutstandingRequest();
    });

    //6.
    it('ServiceTestSpec', function () {

        var returnData = {};

        //7. expectGET to make sure this is called once.
        httpBackend.expectGET("http://localhost:36337/api/EmployeeInfoAPI/1").respond(returnData);

        //8. make the call.
        var returnedPromise = myserv.get(1);

        //9. set up a handler for the response, that will put the result
        // into a variable in this scope for you to test.
        var result;
        returnedPromise.then(function (response) {
            result = response.data;
        });

        //10. flush the backend to "execute" the request to do the expectedGET assertion.
        httpBackend.flush();

        //11. check the result. 
        
        expect(result).toEqual(returnData);

    });


});

The above script code is very simple. The following line numbers matches with comments applied in above JavaScript code.

1. ‘describe’ defines what it is testing. In our case, it is an angular service name passed to it.

2. ‘beforeEach’ allows to execute some code before each test spec. In our case, it is executing the angular module.

3. Load the angular module.

4. Get the service object and $httpBackend, this is a fake HTTP backend implementation for $http so that unit testing of angular service can be made possible.

5. This steps make sure that after each describe no outstanding expectations and request must be pending.

6. This step defines the test specification with name as ServieTestSpec.

7. This step defines the expectGET on the fake $http object which defines expected call to service using the URL.

8. This step makes call to the get() function of service.

9. This step receives response of the call made to the service and store it in result variable.

10. The request is flushed on the httpBackEnd object.

11. Verify the result with the returnedData. This is declared as JavaScript object.

The get() function returns a JavaScript object. If this object matches with the returnedData as JSON object, then the service test will be successful else it will fail.

Add the following contents in karma.config.js

files: [
        "Scripts/angular.js",
        "Scripts/angular-mocks.js",
        "MyScripts/app.js",
        "Test/Test.js"
]

Run the Test from the Command Prompt, using the following command.

karma start karma.conf.js

In the test code, we are passing the URL with the value 1 ‘http://localhost:36337/api/EmployeeInfoAPI/1’ and to the get() function, the input parameter with the value is passed as 1. If this matches with the response, the test will be successfully executed.

successful-test

The Test shows success. If we change parameter for the get() function and if the response does not match with the returnedData, the test will fail.

Conclusion:

Angular.js provides $httpBackEnd object which provides fake implementation for $http which we can use for unit testing Angular services.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!