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 https://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 https://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
· 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.
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)
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades 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), and Front-end technologies like Angular and React. Follow him on twitter @
maheshdotnet or connect with him on
LinkedIn