Jasmine is one of the most widely used testing frameworks to unit-test javascript code in BDD manner. I tried to use it for AngularJS ponents testing. AngularJS documentation provides the following sample code
describe('PasswordController', function() {
beforeEach(module('app'));
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('$scope.grade', function() {
it('sets the strength to "strong" if the password length is >8 chars', function() {
var $scope = {};
var controller = $controller('PasswordController', { $scope: $scope });
$scope.password = 'longerthaneightchars';
$scope.grade();
expect($scope.strength).toEqual('strong');
});
});
});
So the code above uses angular mock library and via dependency injection processes a scope through a controller. Now I have a scope object with functions and objects my controller assigned to it. I can test it well. Happy.
Now the interesting part is if I want to test the functions which are not linked to the scope. For example, the doSomethingVeryCoolThatNeedsTesting
function below
angular.module('app', [])
.controller('PasswordController', function PasswordController($scope) {
$scope.password = '';
$scope.grade = function() {
var size = $scope.password.length;
if (size > 8) {
$scope.strength = 'strong';
} else if (size > 3) {
$scope.strength = 'medium';
} else {
$scope.strength = 'weak';
}
function doSomethingVeryCoolThatNeedsTesting() {
....
}
};
});
It seems that whenever I use $controller('PasswordController', { $scope: $scope });
it returns a populated $scope
object and undefined
controller object.
TL;DR
Is there a way I can test Angular Controller functions which are not linked to the scope?
Jasmine is one of the most widely used testing frameworks to unit-test javascript code in BDD manner. I tried to use it for AngularJS ponents testing. AngularJS documentation provides the following sample code
describe('PasswordController', function() {
beforeEach(module('app'));
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('$scope.grade', function() {
it('sets the strength to "strong" if the password length is >8 chars', function() {
var $scope = {};
var controller = $controller('PasswordController', { $scope: $scope });
$scope.password = 'longerthaneightchars';
$scope.grade();
expect($scope.strength).toEqual('strong');
});
});
});
So the code above uses angular mock library and via dependency injection processes a scope through a controller. Now I have a scope object with functions and objects my controller assigned to it. I can test it well. Happy.
Now the interesting part is if I want to test the functions which are not linked to the scope. For example, the doSomethingVeryCoolThatNeedsTesting
function below
angular.module('app', [])
.controller('PasswordController', function PasswordController($scope) {
$scope.password = '';
$scope.grade = function() {
var size = $scope.password.length;
if (size > 8) {
$scope.strength = 'strong';
} else if (size > 3) {
$scope.strength = 'medium';
} else {
$scope.strength = 'weak';
}
function doSomethingVeryCoolThatNeedsTesting() {
....
}
};
});
It seems that whenever I use $controller('PasswordController', { $scope: $scope });
it returns a populated $scope
object and undefined
controller object.
TL;DR
Is there a way I can test Angular Controller functions which are not linked to the scope?
Share Improve this question asked Jul 1, 2015 at 10:14 Arturs VancansArturs Vancans 4,64014 gold badges49 silver badges79 bronze badges2 Answers
Reset to default 5No. As far as you don't expose the inner controller functions to the outside world those functions are private see the revealing module pattern.
So the problem is not angular neither the testing framework, The problem is the javascript language itself.
If you want to test an inner function you have to make it visible to the outside. The options are:
- Exposed it on the $scope object
- Expose onto any other global object which is strongly discouraged and might be not reachable by the test
i would choose one of those solutions:
- if it's a private function, maybe it should not be tested directly but rather through public api
- if it's an utility function then maybe it should be in its own controller/service as a public api
otherwise you have to pollute your controller api. i advise not to. sooner or later one of the developers will start to use this semi-hidden function