Angular 与 Jasmine:模拟工厂服务
Angular with Jasmine: mocking factory services
我在 Angular JS 中定义了以下控制器,它使用来自 Angular Material 的服务:
angular.module('leopDirective', [])
.controller('MenuCtrl', function ($scope, $timeout, $mdSidenav, $log)
{
$scope.mdSidenav = $mdSidenav;
$scope.close = function () {
$mdSidenav('left').close().then(function () {
$log.debug("close LEFT is done");
$scope.closed = true;
});
};
});
这取决于我试图用我自己的工厂对象模拟的服务 $mdSidenav:
describe('Controller: MenuCtrl', function() {
var $rootScope, $scope, $controller, $q, menuCtrl,
mock__mdSidenav = function(component) {
return {
isMock: true,
component: component,
close: function () {}
}
};
beforeEach(function () {
module('leopDirective', function($provide) {
$provide.value('$mdSidenav', mock__mdSidenav);
});
inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
$controller = $injector.get('$controller');
$q = $injector.get('$q');
$scope = $rootScope.$new();
});
menuCtrl = $controller("MenuCtrl", { $scope: $scope });
});
it('should create the $mdSidenav object', function () {
expect($scope.mdSidenav).toBeDefined();
});
describe('managing $mdSidenav', function () {
it('should close the menu', function () {
var data, deferred = $q.defer(), promise = deferred.promise;
mock__mdSidenav.close = function() {
return promise.then(function (response) {
data = response.success;
});
$rootScope.$digest();
$scope.close();
};
});
});
我有下面的代码plnkr。
显然,唯一不起作用的是我在测试的第二个 "describe" 块中将 $promise 分配给 close() 。执行此测试returns出现如下错误:
TypeError: Cannot read property 'then' of undefined
TypeError: Cannot read property 'then' of undefined
at Scope.$scope.close (app.js:7:35)
是什么让我认为工厂本身或 promise 函数没有正确模拟。
- 这是模拟工厂的正确方法吗?
- 这是创建 returns 承诺方法的正确方法吗?
我不完全确定您要测试的是什么,但这就是您收到此错误消息的原因:
你正在触发 $scope.close(),它没有被模拟。这是 MenuCtrl 中的原始 $scope.close 方法。 close 方法依次触发 $mdSidenav('left').close().then... 并在测试 $mdSidenav('left').close() returns 的参数中undefined 这意味着它没有 then 方法。
如果您想控制发生的事情,您应该为 $scope.close 或 $mdSidenav('left').close 创建一个 spy/mock(这意味着模拟 $mdSidenav return 具有 spy/mock) 的对象的函数。
这道题的答案可以在下面post找到:
使代码正常工作的关键是在模拟对象的定义过程中使用 $q 而无需关心其分辨率。显然,JavaScript 只有在必须使用模拟对象时才会解决它。
我在 Angular JS 中定义了以下控制器,它使用来自 Angular Material 的服务:
angular.module('leopDirective', [])
.controller('MenuCtrl', function ($scope, $timeout, $mdSidenav, $log)
{
$scope.mdSidenav = $mdSidenav;
$scope.close = function () {
$mdSidenav('left').close().then(function () {
$log.debug("close LEFT is done");
$scope.closed = true;
});
};
});
这取决于我试图用我自己的工厂对象模拟的服务 $mdSidenav:
describe('Controller: MenuCtrl', function() {
var $rootScope, $scope, $controller, $q, menuCtrl,
mock__mdSidenav = function(component) {
return {
isMock: true,
component: component,
close: function () {}
}
};
beforeEach(function () {
module('leopDirective', function($provide) {
$provide.value('$mdSidenav', mock__mdSidenav);
});
inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
$controller = $injector.get('$controller');
$q = $injector.get('$q');
$scope = $rootScope.$new();
});
menuCtrl = $controller("MenuCtrl", { $scope: $scope });
});
it('should create the $mdSidenav object', function () {
expect($scope.mdSidenav).toBeDefined();
});
describe('managing $mdSidenav', function () {
it('should close the menu', function () {
var data, deferred = $q.defer(), promise = deferred.promise;
mock__mdSidenav.close = function() {
return promise.then(function (response) {
data = response.success;
});
$rootScope.$digest();
$scope.close();
};
});
});
我有下面的代码plnkr。
显然,唯一不起作用的是我在测试的第二个 "describe" 块中将 $promise 分配给 close() 。执行此测试returns出现如下错误:
TypeError: Cannot read property 'then' of undefined
TypeError: Cannot read property 'then' of undefined
at Scope.$scope.close (app.js:7:35)
是什么让我认为工厂本身或 promise 函数没有正确模拟。
- 这是模拟工厂的正确方法吗?
- 这是创建 returns 承诺方法的正确方法吗?
我不完全确定您要测试的是什么,但这就是您收到此错误消息的原因:
你正在触发 $scope.close(),它没有被模拟。这是 MenuCtrl 中的原始 $scope.close 方法。 close 方法依次触发 $mdSidenav('left').close().then... 并在测试 $mdSidenav('left').close() returns 的参数中undefined 这意味着它没有 then 方法。
如果您想控制发生的事情,您应该为 $scope.close 或 $mdSidenav('left').close 创建一个 spy/mock(这意味着模拟 $mdSidenav return 具有 spy/mock) 的对象的函数。
这道题的答案可以在下面post找到:
使代码正常工作的关键是在模拟对象的定义过程中使用 $q 而无需关心其分辨率。显然,JavaScript 只有在必须使用模拟对象时才会解决它。