Updated April 8, 2023
Introduction to AngularJS Unit Testing
Using AngularJS you are able to build amazing user interfaces, but when the complexity of your project increases, unit testing becomes an important part. To improve your code quality, testing is very important. In Unit testing, we test a component functionality in isolation, without any external resources example DB, files, etc. Unit tests are easy to write and faster in execution. In unit testing, we don’t test the functionality of an app hence low confidence. AngularJS consists of various building blocks like services, components, directives, etc. For each of them, we need to write separate test cases.
Fundamentals of Unit Testing
Following are the fundamentals of Unit Testing.
- We need to follow clean coding practices.
- Apply the same principles as the functional code.
- Test cases are a small function/ method of 10 lines or less.
- Use a proper naming convention.
- They have only a single responsibility i.e. test only one thing.
AngularJS Testing Tools
The testing tools of AngularJS are listed below.
1) Jasmine
Development framework for testing javascript code. It provides functions that help in structuring test cases. As the projects get complex and tests grow, keeping them well-structured and documented is important, and Jasmine helps to achieve this. To use Jasmine with Karma, use the karma-jasmine test runner.
2) Karma
A test runner for writing and running unit tests while developing AngularJS application. It increases developers’ productivity. It will spawn a web server that loads the application code and executes the test cases.
It is a NodeJS application installed through npm/yarn. It can be configured to run against various browsers to ensure that the application works on all available browsers.
3) Angular-Mocks
AngularJS provides the ngMock module, which gives us mock tests. They are used to inject and mock AngularJS services in unit tests.
Environment Setup
- Install NodeJS on your system. (https://nodejs.org/en/download/).
- Install any IDE (like VS code, brackets, etc.).
- Create an empty folder ($mkdir unit testing) in your directory.
- Open the unit testing folder in your IDE. Then open terminal(command prompt) inside your unit testing folder.
- In the terminal follow the below commands one by one:
Create package.json:
npm initInstall Angular:
npm i angular –saveInstall Karma:
npm i -g karma –save -devInstall Jasmine:
npm i karma-jasmine jasmine-core –save -devInstall Angular mocks:
npm i angular-mocks –save -devInstall Karma Chrome browser:
npm i karma-chrome-launcher –save-dev - Create two folders named as app and tests inside the unit testing folder.
- Create karma.config.js. In the terminal give below command:
karma init
It will ask you a set of questions. Select the below answers for it.
-> Select the testing framework as Jasmine.
-> Select Chrome as a browser.
-> Specify the path for your js and spec files (app/*js and tests/*.spec.js)
-> After a few more questions, it will be done.
-> Open karma.config.js files and path and plugins as shown below. Below is the karma.config.js file.
// Karma configuration
module.exports = function(config) {
config.set({
// base path is used to resolve all patterns
basePath: '',
plugins:['karma-jasmine','karma-chrome-launcher'],
frameworks: ['jasmine'],
// list of files to load in the browser
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'app/*.js',
'tests/*.spec.js'
],
// list of files to exclude
exclude: [],
preprocessors: {},
reporters: ['progress'],
// server port
port: 9876,
// enable / disable colors in output
colors: true,
logLevel: config.LOG_INFO,
// enable / disable watch mode for files
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
// how many browser should start simultaneous
concurrency: Infinity
})
}
The folder structured after these steps should be like below:
Example with Implementation
Let us learn examples with implementation.
Testing a Filter
Filters are methods that change data into a human-readable format. In this module, we will create a filter and write unit tests for that filter and check if it is working as expected.
Steps:
Create a file named filter.js in the app folder.
filter.js
angular.module('MyApp', [])
.filter('compute',[function(){
return function(number){
if(number<0){
return 0;
}
return number+1;
}
}])
Now, let’s write the unit test cases to check if the filter is working as expected or not.
Jasmine Framework Methods
- Describe(): It defines a test suite – a group of related tests.
- It() : Defines a specification or test.
- Expect(): It takes an actual value as a parameter and it is chained with a matcher function.
- Matcher function: Takes the expected value as parameters. It is responsible for reporting to Jasmine if the expectation is true or false.
Example:
toBe(‘value’), toContain(‘value’), toEqual(12), toBeNull(), toBeTruthy(), toBeDefined().
Create a file named filter.spec.js in the tests folder.
filter.spec.js
Code:
//1. Describe the object type
describe('Filters', function () {
//2. Load the Angular App
beforeEach(module('MyApp'));
//3. Describe the object by name
describe('compute', function () {
var compute;
//4. Initialize the filter
beforeEach(inject(function ($filter) {
compute = $filter('compute', {});
}));
//5. Write the test in the it block along with expectations.
it('Should return 0 if input is negative', function () {
const result = compute(-1);
expect(result).toBe(0); //pass
});
it('Should increment the input if input is positive', function () {
const result = compute(1);
expect(result).toBe(2);//pass
//expect(compute(3)).toBe(5);//fail
});
});
});
To run the test, give below command in the unit testing folder terminal.
Karma start
or you can set “karma start” in package.json test script and give below command.
npm test
This will open the chrome browser.
Output in Terminal:
Testing a Controller and Service
AngularJS keeps logic separate from the view layer, this makes controllers and services easy to test.
Steps:
1. Create a file named controller.js in the app folder.
controller.js
var app = angular.module('Myapp', [])
app.service('calcService',[
function(){
function square(o1){
return o1*o1;
}
return {square:square};
}
]);
app.controller('MyController', function MyController($scope) {
$scope.title = "Hello MyController";
$scope.square = function() {
$scope.result = calcService.square($scope.number);
}
});
2. Create a file named controller.spec.js in the tests folder.
controller.spec.js
describe('MyController', function() {
var controller, scope;
beforeEach(angular.mock.module('Myapp'));
beforeEach(angular.mock.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('MyController', { $scope : scope });
}));
it('Title should be defined', inject(function ($rootScope, $controller) {
expect(scope.title).toBeDefined();
}));
it('Title as Hello MyController', inject(function ($rootScope, $controller) {
expect(scope.title).toEqual('Hello MyController');
}));
});
describe('square', function(){
var calcService;
beforeEach(function(){
module('Myapp');
inject( function($injector){
calcService = $injector.get('calcService');
});
});
it('should square the number', function(){
var result = calcService.square(3);
expect(result).toBe(9);
});
});
Output in Terminal:
Conclusion
AngularJS applications are composed of modules. At the application level, these are AngularJS modules. At the module level, these are services, factories, components, directives, and filters. Each of them is able to communicate with each other through its external interface. Writing unit test cases for your AngularJS application speeds up your debugging and development process.
Recommended Articles
This is a guide to AngularJS Unit Testing. Here we discuss the introduction and Fundamentals of Unit Testing along with AngularJS Testing Tools and Example with Implementation. You may also look at the following articles to learn more –