Unit Testing Your AngularJS Applications With Jasmine

Since the role of JavaScript is increasing day by day, In my recent projects, currently we are using Dojo and AngularJS part SOA based projects. My managers are forcing me to use TDD style of development including JavaScript code. I have been able to find a few interesting tools to support Test Driven Development (TDD) with JavaScript and that are also well integrated with Visual Studio 2012/2013. I want to share that with you in this article.

Currently used tools in my JavaScript projects for Unit Testing:

  • Jasmine: Jasmine is a behavior-driven development framework ( BDD ) for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.

  • Test Runner: Apart from the selection of testing framework, now need to choose a task runner. All the below examples “Karma” is used as test runner.

  • Angular- mock: Angular provides its own mocking framework which helps in mocking the dependent objects.

Test-Driven Development (TDD)

Test-Driven Development

Mix of BDD ( Behaviour-Driven Development ) and TDD ( Test-Driven Development ).

Mix of BDD

Advantages of BDD (Behaviour-Driven Development ):

  • Common understanding
  • Externally visible
  • Implementation independent
  • Executable requirements
  • Living documentation
  • Specification by example

AngularJS can be tested in a lot of ways and multiple testing frameworks now available in market. But first choice in today's market is “Jasmine”.

Apart from the selection of testing framework, now need to choose a task runner. But choice for task runner along with testing framework “Jasmine” is Karma. The following examples run by test runner using tool name with “Karma”.

How to Setup the Environment

  1. Create an ASP.NET Project (Created empty ASP.NET MVC Project with Unit Tests).

    MVC Project

  2. Install Jasmine from the Nuget package manager.

    Install Jasmine

  3. Install Unit Test runner Karma from Nuget package manager.

    Nuget package manager

  4. Sample project structure in VS 2013.

    Source code

Before writing test let’s understand the following three items which are minimum to write any unit test using Jasmine.

  1. Describe: This is a global function that takes string and function as parameter which represents a suite of test. In another way, it provides us a way to group multiple tests.

  2. beforeEach and afterEach: Need to execute some code— before and after each spec similar to NUnit test method initialize the test cases ( init ) and cleanup some test data etc. (cleanup).

  3. It: This is another function which is written inside global function and takes two parameter as above string and function and this function is actual test.

  4. Expect: It takes the function that need to be tested as parameter and provide a list of matchers to match the result.

Example of Unit Test

  1. describe("A Test Suite Name", function() {  
  2.    it("can add two positive integers", function() {  
  3.       expect(calculator.add(5, 12)).toEqual(17);  
  4.    });  
  5. });  
Sample Jasmine Test
  1. describe("CreateLayerLauncherCtrl: specifications", function ()  
  2. {  
  3.     "use strict";  
  4.     var scope, rootScope, controller, mapConfigSrvc, $q;  
  5.     beforeEach(module("connect"));  
  6.     beforeEach(module(function ($provide, $translateProvider)  
  7.     {  
  8.         $provide.value('$state',  
  9.         {  
  10.             go: function () {}  
  11.         });  
  12.         $translateProvider.useLoader();  
  13.         $translateProvider.translations('en',  
  14.         {});  
  15.         $translateProvider.use('en');  
  16.     }));  
  17.     it("should check if annotation tools, thematic maps creation, querying functionality are disabled", function ()  
  18.     {  
  19.         var $scope = {};  
  20.         controller('createLayerLauncherCtrl',  
  21.         {  
  22.             $scope: $scope,  
  23.             mapConfigSrvc: mapConfigSrvc  
  24.         });  
  25.         rootScope.$digest();  
  26.         expect($scope.annotationDisabled).toBeTruthy();  
  27.     });  
  28. });  
  29. beforeEach(inject(function ($injector)  
  30. {  
  31.     rootScope = $injector.get('$rootScope');  
  32.     scope = rootScope.$new();  
  33.     controller = $injector.get('$controller');  
  34.     mapConfigSrvc = $injector.get('mapConfigSrvc');  
  35.     $q = $injector.get('$q');  
  36.     var configObj = {  
  37.         disableAnnotation: true,  
  38.         disableThematic: true,  
  39.         mapView:  
  40.         {  
  41.             disableQueryView: "true"  
  42.         }  
  43.     };  
  44.     spyOn(mapConfigSrvc, 'getConfig').and.returnValue($q.when(configObj));  
  45. }));  
My AngularJS app
  1. angular.module("connect.panel").controller("createLayerLauncherCtrl", ["$scope""mapConfigSrvc",  
  2.     function ($scope, mapConfigSrvc)  
  3.     {  
  4.         $scope.annotationDisabled = false;  
  5.         $scope.endUserThematicDisabled = false;  
  6.         $scope.disableQueryView = false;  
  7.         mapConfigSrvc.getConfig().then(function (config)  
  8.         {  
  9.             $scope.annotationDisabled = config.disableAnnotation;  
  10.             $scope.endUserThematicDisabled = config.disableThematic;  
  11.             $scope.disableQueryView = config.mapView.disableQueryView === "true" ? true : false;  
  12.         });  
  13.     }  
  14. ]);  
Run your test with task runner using Karma from command line:
  1. # Start Karma using your configuration:  
  2. karma start MyTest.conf.js  
Or directly use the following command to run specific JavaScript file.

karma start my.conf.js --log-level debug --single-run

Sample MyTest.conf.js
  1. // Karma configuration  
  2. module.exports = function (config)  
  3. {  
  4.     config.set(  
  5.     {  
  6.         // base path that will be used to resolve all patterns (eg. files, exclude)  
  7.         basePath: '',  
  8.         // frameworks to use  
  9.         frameworks: ['jasmine'],  
  10.         // list of files / patterns to load in the browser  
  11.         files: ['TestScripts/DefaultTest.js.js'],  
  12.         // list of files to exclude  
  13.         exclude: ['Scripts/*.min.js'],  
  14.         // preprocess matching files before serving them to the browser  
  15.         preprocessors:  
  16.         {},  
  17.         // test results reporter to use  
  18.         // possible values: 'dots', 'progress'  
  19.         reporters: ['progress''xml'],  
  20.         // web server port  
  21.         port: 9876,  
  22.         // enable / disable colors in the output (reporters and logs)  
  23.         colors: true,  
  24.         // level of logging  
  25.         // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG  
  26.         logLevel: config.LOG_INFO,  
  27.         // enable / disable watching file and executing tests whenever any file changes  
  28.         autoWatch: false,  
  29.         // start these browsers  
  30.         browsers: ['PhantomJS'],  
  31.         // Continuous Integration mode  
  32.         // if true, Karma captures browsers, runs the tests and exits  
  33.         singleRun: true  
  34.     });  
  35. };  
Conclusion

AngularJS can be tested in a lot of ways, by lots of testing frameworks. Jasmine – karma is the best combination to make your tests run on platform independent and well suited for mobile development also. Install Karma and Jasmine on NodeJS using NPM (Node Package Manager) using the following commands:

 

  • npm install karma --save-dev.
  • npm install karma-jasmine --save-dev.