如何使用 Jasmine 监视控制器方法?
How do I spy on a controller method using Jasmine?
我正在使用 "controller as" 语法来创建我的控制器。我有一个私有初始化函数,它调用一个函数来加载默认数据。
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
var mc = this;
mc.dataLoaded = false;
function init() {
mc.loadData();
}
mc.loadData = function(){
mc.dataLoaded = true;
}
init();
});
在我的测试中,我创建了一个间谍来检查 loadData
函数是否被调用。虽然我可以通过测试 mc.dataLoaded
标志来验证该函数是否已被调用,但我的间谍似乎没有记录被调用的函数。如何让间谍正确记录函数调用?
describe('Testing a Hello World controller', function() {
var $scope = null;
var ctrl = null;
//you need to indicate your module in a test
beforeEach(module('plunker'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('MainCtrl as mc', {
$scope: $scope
});
spyOn($scope.mc, 'loadData').and.callThrough();
}));
it('should call load data', function() {
expect($scope.mc.loadData).toHaveBeenCalled();
//expect($scope.mc.dataLoaded).toEqual(false);
});
});
这行序列:
ctrl = $controller('MainCtrl as mc', {
$scope: $scope
});
spyOn($scope.mc, 'loadData').and.callThrough();
意味着 Jasmine 间谍是在之后创建的,控制器已经被 $controller 实例化了。在创建间谍之前,init
函数已经执行。
您也不能切换行,因为 MainCtrl 需要存在才能监视其上的方法。
如果 init
函数调用另一个服务,则监视该服务的方法并断言该服务被正确调用。如果 MainCtrl 只是在内部做某事,则测试其结果,例如,通过断言控制器的 data/properties 已更新。如果它足够琐碎,甚至可能不值得测试。
此外,由于您使用控制器作为语法,您可以通过调用 $controller 的 return 值引用控制器,而不是直接访问范围:
ctrl = $controller('MainCtrl as mc', {
$scope: $scope
});
ctrl.loadData === $scope.mc.loadData; // true
我找到了一个可以避免更换控制器的解决方案。我在测试套件的 beforeEach
方法中包含了一个 $state
模拟服务,并给它一个 reload
模拟方法:
beforeEach(inject(function ($controller, $rootScope) {
stateMock = {
reload: function() {
myCtrl = $controller('MyCtrl');
}
};
...
然后在 jasmine 测试中,我可以简单地调用 stateMock.reload()
来重新初始化我的控制器,同时保留我在另一个 beforeEach
块中声明的间谍。
我正在使用 "controller as" 语法来创建我的控制器。我有一个私有初始化函数,它调用一个函数来加载默认数据。
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
var mc = this;
mc.dataLoaded = false;
function init() {
mc.loadData();
}
mc.loadData = function(){
mc.dataLoaded = true;
}
init();
});
在我的测试中,我创建了一个间谍来检查 loadData
函数是否被调用。虽然我可以通过测试 mc.dataLoaded
标志来验证该函数是否已被调用,但我的间谍似乎没有记录被调用的函数。如何让间谍正确记录函数调用?
describe('Testing a Hello World controller', function() {
var $scope = null;
var ctrl = null;
//you need to indicate your module in a test
beforeEach(module('plunker'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('MainCtrl as mc', {
$scope: $scope
});
spyOn($scope.mc, 'loadData').and.callThrough();
}));
it('should call load data', function() {
expect($scope.mc.loadData).toHaveBeenCalled();
//expect($scope.mc.dataLoaded).toEqual(false);
});
});
这行序列:
ctrl = $controller('MainCtrl as mc', {
$scope: $scope
});
spyOn($scope.mc, 'loadData').and.callThrough();
意味着 Jasmine 间谍是在之后创建的,控制器已经被 $controller 实例化了。在创建间谍之前,init
函数已经执行。
您也不能切换行,因为 MainCtrl 需要存在才能监视其上的方法。
如果 init
函数调用另一个服务,则监视该服务的方法并断言该服务被正确调用。如果 MainCtrl 只是在内部做某事,则测试其结果,例如,通过断言控制器的 data/properties 已更新。如果它足够琐碎,甚至可能不值得测试。
此外,由于您使用控制器作为语法,您可以通过调用 $controller 的 return 值引用控制器,而不是直接访问范围:
ctrl = $controller('MainCtrl as mc', {
$scope: $scope
});
ctrl.loadData === $scope.mc.loadData; // true
我找到了一个可以避免更换控制器的解决方案。我在测试套件的 beforeEach
方法中包含了一个 $state
模拟服务,并给它一个 reload
模拟方法:
beforeEach(inject(function ($controller, $rootScope) {
stateMock = {
reload: function() {
myCtrl = $controller('MyCtrl');
}
};
...
然后在 jasmine 测试中,我可以简单地调用 stateMock.reload()
来重新初始化我的控制器,同时保留我在另一个 beforeEach
块中声明的间谍。