Introduction
One of the main features of AngularJS is that we can write unit tests. Testing individual units of code is Unit testing. One of the common unit testing framework used for writing Angular unit tests is Jasmine.
Jasmine
Jasmine is a behavior driven development (BDD) framework for JavaScript. This framework can be used with a Test Driven Development (TDD) approach also. It offers structure for organizing the tests and functions for making assertions. It has a Simple syntax and language construct. Another main feature of Jasmine is that it is independent of Browser, DOM or any other JS framework.
First Look into Jasmine
Some terminology used in Jasmine code:
Spec
: Spec
is Specifications. It is part of terminology of BDD. Consider it to be a logical grouping of tests. Describe
: Describe
function represents a specification (logical grouping of tests). It describes a test. It
: It
function indicates a test within the logical grouping. Expect
: Expect
(Expectation) takes in a value, called the actual, which we wish to test. toBe
: toBe
function takes in an expression which is called a Matcher. Each matcher does a Boolean comparison between the actual and expected values. beforeEach
: It is a function that lets the users to run code before each test.
Setting Up Jasmine
For integrating Jasmine in your code, you need to download some script files and CSS file provided by Jasmine git repo. You can find the files in the below link or you can simply include the cdn links in your application.
Jasmine Home Link -> https://jasmine.github.io/2.5/introduction
CDNs
- https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine.min.js
- https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine-html.min.js
- https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/boot.min.js
- https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine.min.css
Create an HTML file and include these script files and the CSS. Run the HTML file and you should see Jasmine UI as below:
A Simple Jasmine Code
Look at the below HTML code. The script
tags include the required Jasmine script files for successful execution of the test code. Jasmine CSS file is also included in the code which helps in displaying the Jasmine UI for test execution.
<html>
<head>
<link rel="stylesheet" type="text/css"
href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine.min.js">
</script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine-html.min.js">
</script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/boot.min.js">
</script>
</head>
<body>
</body>
<script type="text/javascript">
describe(‘addition’, function() {
it('3 + 4 should equal 7', function() {
expect(3 + 4).toBe(6);
});
});
</script>
</html>
We have written the test code enclosed in script
tags. We have described a spec ‘addition’ with a test that sum of 3 and 4 equals 6, which is wrong. If we run the test, then the display would be:
Now, let us pass the test by changing the 'it
' function as:
it ('3 + 4 should equal 7', function() {
expect(3 + 4).toBe(7);
});
Then the result will be:
Writing Test for a Controller
Now, we’ll apply the unit tests for an angular Controller. Controller in Angular JS is easy to test since Angular separates logic from view layer. Consider the below Angular controller code. A multiplyApp
module is created, and a controller, MultiplyController
having function ‘product
’ for calculating product of two numbers.
MultiplyCtrl.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js">
</script>
<script>
angular.module('multiplyApp', []);
angular.module('multiplyApp').controller
('MultiplyController', function MultiplyController($scope) {
$scope.z = 0;
$scope.product = function() {
$scope.z = $scope.x * $scope.y;
}
});
</script>
</head>
<body ng-app="multiplyApp">
<div ng-controller="MultiplyController">
<input ng-model="x" type="number">
<input ng-model="y" type="number">
{{z}}
<input type="button"
ng-click="product()" value="Multiply">
</div>
</body>
</html>
Now, we’ll write the test code for this controller. Since controllers are unavailable on global scope, angular.mock.inject
is used to inject the controller first. We’ll use module function which is provided by angular-mocks. By using the ngMock
functionality, we register the instance of the app.
beforeEach(angular.mock.inject(function(_$controller_) {
$controller = _$controller_;
}));
Now, we’ll get the instance of MultiplyController
using $controller
service.
var controller = $controller('MultiplyController', {$scope: $scope});
The parameters in curly brackets are the arguments of controller itself. The $scope
object is the only argument for the controller. It can be represented by a simple JS object.
var $scope = {};
var controller = $controller('MultiplyController', {$scope: $scope});
$scope.x = 2;
$scope.y = 3;
We can also read properties of the object as:
expect($scope.z).toBe(6);
Invoking functions on scope objects is the same as we do for JavaScript functions:
$scope.product();
Now, we have our test code:
describe('multiply', function() {
beforeEach(angular.mock.module('multiplyApp'));
var $controller;
beforeEach(angular.mock.inject(function(_$controller_) {
$controller = _$controller_;
}));
describe('product', function() {
it ('2*3 should equal 6', function() {
var $scope = {};
var controller =
$controller('MultiplyController', {$scope: $scope});
$scope.x = 2;
$scope.y = 3;
$scope.product();
expect($scope.z).toBe(6);
});
});
});
The above code tests the MultiplyController
with a simple test case, whether 2 multiplied by 3 gives 6 or not. Include the above code in your Angular application, MultiplyCtrl.html, inside script
tags. You can write the tests in a separate JS file and include it in the application. For this sample, we will write the test code in the same MultiplyCtrl.html file. If you want to add another test, we can add in the test code but it will not automatically run once added. To do that, we use Karma test runner.
Also include the Jasmine references mentioned in the previous section along with angular-mocks
script for ngMock
functionality and give the code a run. You should see the test specs in the browser.
Conclusion
Unit testing reduces the amount of errors or bugs during application development. Jasmine is one of the most commonly used frameworks for Unit testing in Angular JS. It is easy to integrate into the code and can be handled easily for Unit testing angular code. Since it has a simple syntax and language construct, it won’t take much time to learn Jasmine and start coding. Hope this article helps in understanding the awesome Jasmine framework for writing test cases for Angular Code.
References