如何使用 Jasmine 测试 _.defer(),AngularJs
How to test _.defer() using Jasmine, AngularJs
我已经问过这个 重点是范围在终端中不存在,但在 Chrome 调试工具中存在。尽管有答案,但它没有得到修复。
问题是测试波纹管指令的正确语法是什么,尤其是 expect(scope.measurementScroll).toBe(true);
行。在网上搜索时,我找不到任何类似的问题,大多数问题都与 $q.defer()
有关,在我的例子中,有下划线方法 _.defer()
控制器
'use strict';
angular.module('myApp')
.controller('MeasurementsTimelineCtrl', ['$scope', '$state', 'Measurements', function($scope, $state, Measurements) {
$scope.measurements = null;
var userId = $scope.currentUser ? $scope.currentUser.id : null;
if (userId) {
var listOfMeasurements = Measurements.userIndex(userId);
listOfMeasurements.then(function(data){
$scope.measurements = data;
$scope.$broadcast('measurements-updated', $scope.measurements);
});
}
}]);
指令:
'use strict';
angular.module('myApp')
.directive('dashboardMeasurementTimeline', ['$window', function($window) {
return {
restrict: 'E',
templateUrl: 'myView.html',
controller: 'MeasurementsTimelineCtrl',
link: function(scope, element){
scope.$on('measurements-updated', function(measurements) {
_.defer(function(){
if(measurements) {
scope.measurementScroll = true;
}
});
});
}
};
}]);
测试
'use strict';
describe('Directive: dashboardMeasurementTimeline', function () {
var $rootScope, $compile, element, scope;
beforeEach(function() {
module('myApp');
inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
});
scope = $rootScope.$new();
element = angular.element('<dashboard-measurement-timeline></dashboard-measurement-timeline>');
element = $compile(element)(scope);
scope.currentUser = {id : 'someId'};
scope.$digest();
scope.measurements = [{id: 'someId', time_of_test: 'Tue, 30 Dec 2014 14:00:00 -0000'},
{id: 'someId', time_of_test: 'Thu, 20 Nov 2014 03:00:00 -0000'},];
scope.$broadcast('measurements-updated', scope.measurements);
scope.$apply();
});
it('should assign true value to measurementScroll', function () {
expect(scope.measurementScroll).toBe(true);
});
});
您可以通过注入一个模拟下划线库来做到这一点,并在测试中定义一个 defer
函数。一种方法是定义您自己的工厂,_
,然后可以轻松地对其进行模拟:
app.factory('_', function($window) {
return $window._;
});
然后在指令中,你必须通过注入来使用它:
app.directive('dashboardMeasurementTimeline', ['_', function(_) {
在测试中,你可以模拟它:
var deferCallback;
beforeEach(module(function($provide) {
deferCallback = null;
$provide.value('_', {
defer: function(callback) {
deferCallback = callback;
}
});
}));
这意味着该指令将使用模拟 _
而不是真正的指令,它将传递给 defer
的回调保存为 deferCallback
以便您可以在需要时调用它:
scope.$broadcast('measurements-updated', scope.measurements);
deferCallback();
这使测试同步,这通常比使用 done()
更好,因为它使测试尽可能快。
看到上面的工作
@Michal Charezma,为实际上是一个解决方案的问题提供了一个很好的解决方案,但事实证明它对其余 _
函数有一些其他限制。
例如:
angular.element(scrollContainer).bind('scroll', _.throttle(scope.disableButtons, 500));
引发错误,指出 throttle
未定义。
按照@Michal 的逻辑,找到了另一个解决方案,可以让 _.throttle()
等功能正常工作。因此,不是导入 _
而是使用:
app.factory('_', function($window) {
return $window._;
});
只能模拟 defer
函数,从规范来看:
var deferCallback = $window._.defer.mostRecentCall.args[0];
deferCallback()
如果你没有将 lodash 作为要注入的服务,你可以只监视 defer
方法,如果你关心传递的函数的执行,那么你可以设置一个 callFake
并调用传递给真实 defer
:
的参数函数
spyOn(_, 'defer').and.callFake(f => f());
更深入一点,假设您有以下调用:
function toTest() {
_.defer(() => service.callAFunction());
}
然后在你的测试中你可以说:
it('should call service.callAFunction', () => {
spyOn(service, 'callAFunction');
spyOn(_, 'defer').and.callFake(f => f());
toTest();
expect(_.defer).toHaveBeenCalled();
expect(service.callAFunction).toHaveBeenCalled();
}
我已经问过这个
问题是测试波纹管指令的正确语法是什么,尤其是 expect(scope.measurementScroll).toBe(true);
行。在网上搜索时,我找不到任何类似的问题,大多数问题都与 $q.defer()
有关,在我的例子中,有下划线方法 _.defer()
控制器
'use strict';
angular.module('myApp')
.controller('MeasurementsTimelineCtrl', ['$scope', '$state', 'Measurements', function($scope, $state, Measurements) {
$scope.measurements = null;
var userId = $scope.currentUser ? $scope.currentUser.id : null;
if (userId) {
var listOfMeasurements = Measurements.userIndex(userId);
listOfMeasurements.then(function(data){
$scope.measurements = data;
$scope.$broadcast('measurements-updated', $scope.measurements);
});
}
}]);
指令:
'use strict';
angular.module('myApp')
.directive('dashboardMeasurementTimeline', ['$window', function($window) {
return {
restrict: 'E',
templateUrl: 'myView.html',
controller: 'MeasurementsTimelineCtrl',
link: function(scope, element){
scope.$on('measurements-updated', function(measurements) {
_.defer(function(){
if(measurements) {
scope.measurementScroll = true;
}
});
});
}
};
}]);
测试
'use strict';
describe('Directive: dashboardMeasurementTimeline', function () {
var $rootScope, $compile, element, scope;
beforeEach(function() {
module('myApp');
inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
});
scope = $rootScope.$new();
element = angular.element('<dashboard-measurement-timeline></dashboard-measurement-timeline>');
element = $compile(element)(scope);
scope.currentUser = {id : 'someId'};
scope.$digest();
scope.measurements = [{id: 'someId', time_of_test: 'Tue, 30 Dec 2014 14:00:00 -0000'},
{id: 'someId', time_of_test: 'Thu, 20 Nov 2014 03:00:00 -0000'},];
scope.$broadcast('measurements-updated', scope.measurements);
scope.$apply();
});
it('should assign true value to measurementScroll', function () {
expect(scope.measurementScroll).toBe(true);
});
});
您可以通过注入一个模拟下划线库来做到这一点,并在测试中定义一个 defer
函数。一种方法是定义您自己的工厂,_
,然后可以轻松地对其进行模拟:
app.factory('_', function($window) {
return $window._;
});
然后在指令中,你必须通过注入来使用它:
app.directive('dashboardMeasurementTimeline', ['_', function(_) {
在测试中,你可以模拟它:
var deferCallback;
beforeEach(module(function($provide) {
deferCallback = null;
$provide.value('_', {
defer: function(callback) {
deferCallback = callback;
}
});
}));
这意味着该指令将使用模拟 _
而不是真正的指令,它将传递给 defer
的回调保存为 deferCallback
以便您可以在需要时调用它:
scope.$broadcast('measurements-updated', scope.measurements);
deferCallback();
这使测试同步,这通常比使用 done()
更好,因为它使测试尽可能快。
@Michal Charezma,为实际上是一个解决方案的问题提供了一个很好的解决方案,但事实证明它对其余 _
函数有一些其他限制。
例如:
angular.element(scrollContainer).bind('scroll', _.throttle(scope.disableButtons, 500));
引发错误,指出 throttle
未定义。
按照@Michal 的逻辑,找到了另一个解决方案,可以让 _.throttle()
等功能正常工作。因此,不是导入 _
而是使用:
app.factory('_', function($window) {
return $window._;
});
只能模拟 defer
函数,从规范来看:
var deferCallback = $window._.defer.mostRecentCall.args[0];
deferCallback()
如果你没有将 lodash 作为要注入的服务,你可以只监视 defer
方法,如果你关心传递的函数的执行,那么你可以设置一个 callFake
并调用传递给真实 defer
:
spyOn(_, 'defer').and.callFake(f => f());
更深入一点,假设您有以下调用:
function toTest() {
_.defer(() => service.callAFunction());
}
然后在你的测试中你可以说:
it('should call service.callAFunction', () => {
spyOn(service, 'callAFunction');
spyOn(_, 'defer').and.callFake(f => f());
toTest();
expect(_.defer).toHaveBeenCalled();
expect(service.callAFunction).toHaveBeenCalled();
}