我正在为我的控制器编写一些使用promises的单元测试。 基本上这个:
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.$apply(function () {
$scope.contacts = data;
});
});
我已经模拟了我的UserService。这是我的单元测试:
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;
});
然而,这打破了我的控制器的功能......那么我该怎么办?
感谢您的回复,$ apply不会发生在UserService中。它在控制器中。像这样:
编辑: $ apply正在这样的控制器中发生。
appController.controller('ContactDetailController', function ($scope, $routeParams, UserService) {
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.$apply(function () {
$scope.contacts = data;
});
});
Real UserService:
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;
}
答案 0 :(得分:1)
您的UserService中存在一些问题。
您使用的是Q
,而不是$q
。很难确切地知道它具有什么效果,除了它在使用Angular时不常见,并且可能会影响then
回调运行的确切时间。
当你真的不需要时,你实际上是在getUser
创建一个承诺(可以看作是anti-pattern)。从success
承诺返回的承诺的$http
函数我认为通常比它的价值更麻烦。根据我的经验,通常最好只使用标准then
函数,因为您可以为它返回一个经过后处理的值并使用标准的promise链接:
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();