A test for a controller follows similar a pattern to the one for a service. Let’s have a look at the fragment of the ProjectsEditCtrl
controller from the sample application. This controller in question is responsible for the editing projects in the administration part of the application. Here we are going to test methods of the controller responsible for adding and removing project’s team members:
angular.module('admin-projects', [])
.controller('ProjectsEditCtrl', function($scope, project) {
$scope.project = project;
$scope.removeTeamMember = function(teamMember) {
var idx = $scope.project.teamMembers.indexOf(teamMember);
if(idx >= 0) {
$scope.project.teamMembers.splice(idx, 1);
}
};
//other methods of the controller
});
The logic of the presented controllers is not complex and will let us to focus on the test itself:
describe('ProjectsEditCtrl tests', function () { var $scope; beforeEach(module('admin-projects')); beforeEach(inject(function ($rootScope) { $scope = $rootScope.$new(); })); it('should remove an existing team member', inject(function ($controller) { var teamMember = {}; $controller('ProjectsEditCtrl', { $scope: $scope, project: { teamMembers: [teamMember] } }); //verify the initial setup expect($scope.project.teamMembers).toEqual([teamMember]); //execute and verify results $scope.removeTeamMember(teamMember); expect($scope.project.teamMembers).toEqual([]); })); });
The removeTeamMember
method that we want to test here will be defined on a $scope
and it is the ProjectsEditCtrl
controller that defines this method. To effectively test the removeTeamMember
method we need to create a new scope, a new instance of the ProjectsEditCtrl
controller and link the two together. Essentially we need to manually do the job of the ng-controller
directive.
Let’s turn our attention to the beforeEach
section for one more moment, as there are interesting things going on in there. Firstly we are getting access to the $rootScope
service and creating a new $scope
instance ($scope.$new()
). We do so to simulate what would happen in a running application, where the ng-controller
directive would create a new scope.
To create an instance of the controller we can use the $controller
service (please notice how the inject
function can be placed on the beforeEach
section as well as on the it
level).
Note
Look how easy it is to specify controller’s constructor arguments while invoking the $controller
service. This is dependency injection at its best; we can provide both a fake scope and test data to exercise controller’s implementation in complete isolation.
Comments