Unit testing in AngularJS is primarily done using Karma as the test runner and Jasmine as the testing framework. Karma helps execute tests in multiple browsers, while Jasmine provides a clean syntax for writing test cases.
In this guide, we will cover:
- Setting up Karma and Jasmine
- Writing test cases
- Mocking dependencies
- Running tests and analyzing results
1. Setting Up Karma and Jasmine
To start writing unit tests, follow these steps:
Step 1: Install Required Packages
Ensure you have Node.js installed, then install Karma and Jasmine globally:
shCopyEditnpm install -g karma karma-cli jasmine-core karma-jasmine karma-chrome-launcher karma-ng-html2js-preprocessor
Step 2: Initialize Karma
Run the following command to set up Karma:
karma init karma.conf.js
This will prompt you to answer some configuration questions. For a typical AngularJS project:
- Test framework? → Jasmine
- Use Require.js? → No
- Which browser? → Chrome
- Where to find test files? → Use a glob pattern like
test/**/*.spec.js
2. Writing Unit Tests in Jasmine
Jasmine provides functions like describe()
, it()
, and expect()
to structure and define test cases.
Basic Syntax
describe('Suite Name', function() {
it('should perform a basic test', function() {
expect(true).toBe(true);
});
});
3. Testing an AngularJS Controller
Assume we have a simple CalculatorController
in our AngularJS app:
Controller Code (calculatorController.js
)
app.controller('CalculatorController', function($scope) {
$scope.add = function(a, b) {
return a + b;
};
});
Test Case for Controller (calculatorController.spec.js
)
describe('CalculatorController', function() {
var $controller, $rootScope;
beforeEach(module('myApp')); // Load the module
beforeEach(inject(function(_$controller_, _$rootScope_) {
$controller = _$controller_;
$rootScope = _$rootScope_;
}));
it('should add two numbers correctly', function() {
var $scope = $rootScope.$new();
var controller = $controller('CalculatorController', { $scope: $scope });
expect($scope.add(3, 5)).toBe(8);
expect($scope.add(-2, 2)).toBe(0);
});
});
4. Testing AngularJS Services
Service Code (mathService.js
)
app.service('MathService', function() {
this.multiply = function(a, b) {
return a * b;
};
});
Test Case for Service (mathService.spec.js
)
describe('MathService', function() {
var MathService;
beforeEach(module('myApp'));
beforeEach(inject(function(_MathService_) {
MathService = _MathService_;
}));
it('should multiply two numbers correctly', function() {
expect(MathService.multiply(3, 4)).toBe(12);
expect(MathService.multiply(0, 5)).toBe(0);
});
});
5. Mocking Dependencies Using $q
and $httpBackend
Service with $http
(dataService.js
)
app.service('DataService', function($http) {
this.getData = function() {
return $http.get('/api/data');
};
});
Mocking HTTP Requests in the Test (dataService.spec.js
)
describe('DataService', function() {
var DataService, $httpBackend;
beforeEach(module('myApp'));
beforeEach(inject(function(_DataService_, _$httpBackend_) {
DataService = _DataService_;
$httpBackend = _$httpBackend_;
}));
it('should fetch data from API', function() {
var mockData = { name: "Test User" };
// Mock HTTP response
$httpBackend.whenGET('/api/data').respond(200, mockData);
var result;
DataService.getData().then(function(response) {
result = response.data;
});
$httpBackend.flush(); // Resolve the HTTP request
expect(result).toEqual(mockData);
});
});
Why Use $httpBackend
?
- Simulates API calls without making real HTTP requests.
- Controls responses and avoids network dependency in tests.
6. Running Tests
Once test cases are written, run Karma:
karma start karma.conf.js
To auto-run tests on file changes, enable auto-watch in karma.conf.js
:
autoWatch: true
7. Code Coverage with Karma and Istanbul
To generate a test coverage report:
- Install the coverage plugin:
npm install --save-dev karma-coverage
- Update
karma.conf.js
:reporters: ['progress', 'coverage'], preprocessors: { 'src/**/*.js': ['coverage'] }, coverageReporter: { type: 'html', dir: 'coverage/' }
- Run Karma and check the
coverage/
folder for reports.