Javascript 角度控制器的设计与测试
我正在为我的控制器编写一些单元测试,它使用承诺。 基本上:Javascript 角度控制器的设计与测试,javascript,angularjs,unit-testing,promise,q,Javascript,Angularjs,Unit Testing,Promise,Q,我正在为我的控制器编写一些单元测试,它使用承诺。 基本上: UserService.getUser($routeParams.contactId).then(function (data) { $scope.$apply(function () { $scope.contacts = data; }); }); 我嘲笑了我的用户服务。这是我的单元测试: beforeEach(inject(function ($rootScope, $controller, $q,
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.$apply(function () {
$scope.contacts = data;
});
});
我嘲笑了我的用户服务。这是我的单元测试:
beforeEach(inject(function ($rootScope, $controller, $q, $routeParams) {
$routeParams.contactId = contactId;
window.localStorage.clear();
UserService = {
getUser: function () {
def = $q.defer();
return def.promise;
}
};
spyOn(UserService, 'getUser').andCallThrough();
scope = $rootScope.$new();
ctrl = $controller('ContactDetailController', {
$scope: scope,
UserService:UserService
});
}));
it('should return 1 contact', function () {
expect(scope.contacts).not.toBeDefined();
def.resolve(contact);
scope.$apply();
expect(scope.contacts.surname).toEqual('NAME');
expect(scope.contacts.email).toEqual('EMAIL');
});
这给了我以下错误:
Error: [$rootScope:inprog] $digest already in progress
现在,在控制器中删除$scope.$apply会导致测试通过,如下所示:
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.contacts = data;
});
然而,这破坏了我的控制器的功能。。。那我在这里该怎么办
感谢您的回复,UserService中没有发生$apply。它在控制器里。像这样:
编辑:
$apply在控制器中发生的情况如下
appController.controller('ContactDetailController', function ($scope, $routeParams, UserService) {
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.$apply(function () {
$scope.contacts = data;
});
});
实时用户服务:
function getUser(user) {
if (user === undefined) {
user = getUserId();
}
var deferred = Q.defer();
$http({
method: 'GET',
url: BASE_URL + '/users/' + user
}).success(function (user) {
deferred.resolve(user);
});
return deferred.promise;
}
您的用户服务中有几个问题
- 您使用的是
,而不是Q
。很难确切知道这有什么影响,除了使用Angular时它不是典型的,并且可能会影响$Q
然后
回调运行的确切时间
- 实际上,您正在
中创建一个承诺,而实际上您并不需要这样做(可以看作是一个承诺)。我认为,getUser
promise返回的promise的$http
功能通常比它的价值更麻烦。根据我的经验,通常最好只使用标准的成功
函数,因为这样您就可以为它返回一个经过后期处理的值,并使用标准的承诺链接:then
function getUser(user) { if (user === undefined) { user = getUserId(); } return $http({ method: 'GET', url: BASE_URL + '/users/' + user }).then(function(response) { return response.data; }); }
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.contacts = data;
});
然后在测试中,在解决承诺调用后,$apply
def.resolve(contact);
scope.$apply();
在测试承诺时,您需要手动运行摘要。是的,您应该在单元测试中手动运行摘要,而您可能不应该在服务中这样做。为什么您的服务有$scope?服务应该充当模型,控制器应该从服务获取数据。如果您发现需要在代码中运行$apply,则可能有问题。作用域上的$apply发生在控制器中。很抱歉造成混淆,请参阅上面帖子中的我的编辑。
UserService
中可能存在问题,因为它正在解决$digest
循环之外的承诺。你能发布它如何获取用户并解析其返回承诺的代码/详细信息吗?@MichalCharemza将其添加到上面的帖子中