Unit testing is referred to as testing of smallest individual parts of an application independently. We will be looking at how to implement unit testing using Jasmine & Karma with an Angular JS application.
What is Jasmine?
Jasmine is a BDD (Behaviour Driven Development) JavaScript testing framework. It provides basic building blocks for writing unit tests for testing JavaScript code.
What is Karma?
Karma is neither a testing framework nor an assertion library but is a tool that allows you to run your JavaScript test cases. Karma supports many JavaScript testing frameworks and Jasmine is one of them. Karma also supports running your test cases inside various browsers and through command line. You can configure Karma to run locally on your development environment as well as CI (Continuous Integration) Server.
Getting Started
We will need to have the necessary environment set up before we start writing the unit test cases using AngularJS, Karma & Jasmine. You will also need to have basic understanding of jQuery and AngularJS.
Set up AngularJS
This article is more about implementing unit test cases using Karma and Jasmine hence in case if you are looking for information on setting up AngularJS then they may go through the links mentioned at the bottom of the article.
Setting up Karma
Karma runs on Node.js so you will need to have Node.js installed. You can download and install Node.js from link mentioned in the sources section below for your respective OS. Once the Node.js installed you can install Karma using following NPM command. It’s always recommended that you install the Karma and it’s plugin to the project’s local directory in the development environment.
> npm install karma --save-dev
Setting up Jasmine
Once Karma is installed you can install Jasmine plugin for karma using following command.
> npm install karma-jasmine --save-dev
Above mentioned commands will install Karma & Jasmine packages into the node_modules folder of your current working directory and it will also update the pakage.json devDependencies. To test if karma is installed properly you run the following command in the command line interface.
>./node_modules/karma/bin/karma start
In real applications It can be annoying to go through node_modules folder to run karma every time, to overcome this you can install karma-cli command line interface plugin which will allow you to run the local version of karma by simply typing karma. Following command will install karma-cli plugin globally.
> npm install -g karma-cli
Configuring Karma
Once you have the karma and karma-jasmine plugin installed you can generate the karma configuration file. Configuration file contains information like location of your source and test files along with other configurations. You can either create the config file manually or use following command to generate the config file.
> karma init karma.conf.js
Once you run above mentioned command, you will need to provide following information.
- Which testing framework do you want to use? (Answer should be Jasmine)
- Do you want to use Require.js?
- Do you want to capture a browser automatically?
- What is the location of your source and test files?
- Should any of the files included by the previous patterns be excluded?
- Do you want Karma to watch all the files and run the tests on change?
Once you have completed the questions, karma.conf.js will be generated with all basic configurations. Remember that when you run karma by default it will look for karma.conf.js configuration file so in case if you are providing any custom name to your config file then make sure you forward that to karma while running karma.
Writing Unit Test Case using Jasmine
After having all set up work done now you can start writing a unit test case as per Jasmine specifications. Like any other coding language or framework Jasmine also has specifications. Some of the basic once are listed below.
-
Suites
Suite’s are like class in object oriented languages like Java, C# which can contain one or more test case methods. In Jasmine you can define a suite by calling global Jasmine global function called describe () which takes two arguments. The first argument is the name of the suite and the second argument is the JavaScript function containing initialization functions and specs.
Describe ("This is a suite",function (){ });
-
Specs
Spec in Jasmine is a test case which can be defined by calling global Jasmine function called it () which again takes two arguments like suite. The first argument is the name of the spec and the second argument is the JavaScript function containing one or more expectations. If one run’s any of the spec temporarily then you can declare it as it(), these spec are called pending specs.
Describe ("This is a suite",function (){ It ("This is a spec",function (){ });});
-
Expectations
Expectation in Jasmine is like assertions. Expectation is built with Jasmine function called expect (). Expect function takes a single argument which represents the actual value and compares it to the expected value with the help of a matcher function. Jasmine’s matcher functions do Boolean comparison between the actual and the expected values. Jasmine framework is loaded with plenty of matchers but if there is a need you can also define you own custom matcher.
Describe ("This is a suite",function (){ it("This is a spec with expectations",function(){ var expectedValue = a; var actualValue = 12; expect(expectedValue).toBe(actualValue ); expect(expectedValue).not.toBe(actualValue); });});
- Setup and Teardown
You can implement initialization and cleanup logic inside the Jasmine’s following global functions.
- The beforeEach() is called once before every spec in the describe is executed
- The afterEach() is called once after every spec in the describe is executed
- The beforeAll() is called only once before any of the specs in the describe is executed
- The afterAll() is called after all the specs in the describe are executed
Spies
A spy creates a mock function for any existing function and tracks call to it along with arguments passed to the function on which a Spy was created.
describe("A spy", function() { var myObj, name = null; beforeEach(function() {myObj = { setName: function(value) { } }; spyOn(myObj, 'setName'); myObj.setName(“MyName”); }); it("spec to track that spy created on myObj.setName was called", function() { expect(myObj.setName).toHaveBeenCalled();});});
Following additional matchers are available specifically for interacting with spies.
- toHaveBeenCalled() : This Matcher returns true if the method on which spy was created is called
- toHaveBeenCalledWith() : This Matcher returns true if any of the call to the function on which Spy was created has the same argument list as declared in the respective Spy’s argument list
You can chain call to a Spy
- and.callThrough() : This tracks all calls to a function but also want to delegate call to the actual implementation.
- and.returnValue() : For all calls to a Spy to return a specific value
- and.callFake() : For a Spy to be delegated to a supplied function
- and.throwError() : For all calls to a Spy to for an error on specific values
Following are some of the methods available for tracking calls to a Spy,
- .calls.any() : Returns true if one or more calls have been made to the Spy. Returns false if no call made to the Spy.
- .calls.count() : Returns the count of how many times the spy was called
- .calls.argsFor(index) : Returns the arguments passed to the call specified in the index param
- .calls.allArgs() : Returns the list of set of arguments made in various calls to the Spy
- .calls.reset() : Resets/clears all the tracking information for a spy
Executing Jasmine Unit Test Cases
Once you have written few jasmine unit test cases and ready to execute them, you can do so by running following command in your command line interface.
> karma start > karma run
Once you run these commands, all the unit test cases will be executed and success/error response will be displayed in the command line interface.
Conclusion
With growing size of the real life applications and increasing dependencies/complexities implementing unit testing on client side has become very significant. Availability of frameworks like AngularJS, Jasmine and Karma has made it fairly simple to implement structured, well-organized and maintainable unit testing in client side code. For further details on the working of the technologies mentioned in this article please visit links mentioned in the sources section at the bottom of this article.
Sources
- Downloading and installing Karma: https://nodejs.org/download
- Jasmine Documentation: http://jasmine.github.io
- Installing AngularJS: https://www.npmjs.com/package/angular
- AngularJS Getting Started: https://docs.angularjs.org/misc/started
- https://docs.angularjs.org/api
- http://www.ng-newsletter.com/posts/beginner2expert-how_to_start.html