The best place to start learning about how to test your Angular code is the Unit Testing section of the AngularJS Developer Guide. Some of the important takeaways from the guide are that
- dependency injection is the best way to get ahold of dependencies for testing purposes. Angular has this built in, but you can help by not manipulating the DOM in your application (e.g., controller) logic.
- use the $compile service to bind scope to a directive's DOM for testing
Some other helpful practices I've discovered through experience:
-
Directives often have their own controller. You can pull this controller out to make testing easier. For instance:
function MyDirectiveCtrl($scope) { // Controller logic for the directive } angular.module('myApp').directive('myDirective', function () { return { // other DDO fields omitted for brevity controller: ['$scope', MyDirectiveCtrl] }; });
-
You can use the
$controller
service to instantiate controllers, and$rootScope.$new()
to create new Scopes, as in the following example:it('should test the directive controller', inject(function ($rootScope, $controller) { var scope = $rootScope.$new(); // this runs the controller logic on the scope $controller('MyDirectiveCtrl', { $scope: scope }); expect(scope.theAnswer).toBe('42'); }));
-
Angular applications often gather resource data from REST or other HTTP APIs. The
$httpBackend
mock makes it easy to fake out these types of services for unit testing. Use it!describe('a resource', function () { var $httpBackend; beforeEach(module('myApp')); beforeEach(inject(function (_$httpBackend_) { $httpBackend = _$httpBackend_; })); afterEach(function () { $httpBackend.verifyNoOutstandingExpectation(); }); it('should expect HTTP requests and provide fake responses', inject(function ($rootScope, $controller) { $httpBackend.expectGET('/api/unicorns/9001') .respond({ name: 'Louie' }); var scope = $rootScope.$new(); $controller('GetThe9001stUnicornCtrl', { $scope: scope }); // Important: HTTP request/responses must be flushed explicitly! $httpBackend.flush(); expect(scope.unicorn.name).toBe('Louie'); })); });
-
Use
$httpBackend.expect()
when the order of HTTP requests and responses matters and you only need one request at a time. Use$httpBackend.when()
when you need to mock multiple requests.