Click here to Skip to main content
14,979,090 members
Articles / DevOps / Unit Testing
Article
Posted 18 Feb 2017

Stats

14.2K views
1 bookmarked

Testing an Angular Controller with Jasmine

Rate me:
Please Sign up or sign in to vote.
5.00/5 (12 votes)
18 Feb 2017CPOL4 min read
Learn how to write unit test cases using Jasmine framework for Angular Controllers

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

  1. https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/jasmine-html.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.5.2/boot.min.js
  4. 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:

Image 1

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
<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:

Image 2

Now, let us pass the test by changing the 'it' function as:

JavaScript
 it ('3 + 4 should equal 7', function() {
        expect(3 + 4).toBe(7);
});

Then the result will be:

Image 3

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
<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.

JavaScript
beforeEach(angular.mock.inject(function(_$controller_) {
                    $controller = _$controller_;
                }));

Now, we’ll get the instance of MultiplyController using $controller service.

JavaScript
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.

JavaScript
var $scope = {};
var controller = $controller('MultiplyController', {$scope: $scope});
$scope.x = 2;
$scope.y = 3;

We can also read properties of the object as:

JavaScript
expect($scope.z).toBe(6);

Invoking functions on scope objects is the same as we do for JavaScript functions:

JavaScript
$scope.product();

Now, we have our test code:

JavaScript
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Naveen Kosana
Software Developer
India India
Software developer in an MNC.

Comments and Discussions

 
-- There are no messages in this forum --