根据Michal Charemza帖子编辑。
我有一个代表angularui模态对话框的服务:
app.factory("dialogFactory", function($modal, $window, $q) { function confirmDeleteDialog() { var modalInstance = $modal.open({ templateUrl: "../application/factories/confirmDeleteDialog.htm", controller: function($scope, $modalInstance) { $scope.ok = function() { $modalInstance.close("true"); }; $scope.cancel = function() { $modalInstance.dismiss("false"); }; } }); return modalInstance.result.then(function(response) { return 'My other success result'; }, function(response) { return $q.reject('My other failure reason'); }); }; return { confirmDeleteDialog: confirmDeleteDialog }; });
如果用户单击对话框中的“确定”,则在调用delete方法时将requestNotificationChannel.deleteMessage(id)执行。
requestNotificationChannel.deleteMessage(id)
$scope.deleteMessage = function(id) { var result = dialogFactory.confirmDeleteDialog(); result.then(function(response) { requestNotificationChannel.deleteMessage(id); }); };
问题是我无法对此进行单元测试。
这是我的考验。我已经正确注入了q服务,但是我不确定应该从"confirmDeleteDialog"间谍那里返回什么…
"confirmDeleteDialog"
describe("has a delete method that should call delete message notification", function() { var deferred = $q.defer(); spyOn(dialogFactory, "confirmDeleteDialog").and.returnValue(deferred.promise); spyOn(requestNotificationChannel, "deleteMessage"); $scope.deleteMessage(5); deferred.resolve(); it("delete message notification is called", function() { expect(requestNotificationChannel.deleteMessage).toHaveBeenCalled(); }); });
但是我正在接受expected spy deleteMessage to have been called。这意味着result.then…部分没有执行。我想念什么?
expected spy deleteMessage to have been called
result.then
要模拟返回承诺的函数,它还需要返回承诺,然后需要将其作为单独的步骤进行解析。
在您的情况下,deferred.resolve()您传递给间谍的内容需要替换为deferred.promise,并且deferred.resolve()分别执行。
deferred.resolve()
deferred.promise
beforeEach(function() { var deferred = $q.defer(); spyOn(dialogFactory, "confirmDeleteDialog").and.returnValue(deferred.promise); spyOn(requestNotificationChannel, "deleteMessage"); $scope.deleteMessage(5); deferred.resolve(); $rootScope.$digest(); }); it("delete message notification is called", function() { expect(requestNotificationChannel.deleteMessage).toHaveBeenCalled(); });
我怀疑您还需要调用$rootScope.$digest(),因为Angular的promise实现与摘要循环相关。
$rootScope.$digest()
另外,与您的问题略有关系,但我认为您无需在中创建自己的延迟对象confirmDeleteDialog。您正在使用的(反)模式已标记为“被遗忘的承诺”,如http://taoofcode.net/promise- anti-patterns/
confirmDeleteDialog
当更简单,使用更少的代码并且我认为可以更好地处理错误时,您可以返回$modal服务创建的承诺:
$modal
var modalInstance = $modal.open({...}); return modalInstance.result;
如果要修改调用函数所看到的内容(根据已解析/拒绝的值),可以通过返回以下结果来创建链式承诺then:
then
var modalInstance = $modal.open({...}); return modalInstance.result.then(function(successResult) { return 'My other success result'; }, function(failureReason) { return $q.reject('My other failure reason'); });
如果您不想向调用者公开函数的内部功能,通常会希望这样做。这类似于在同步编程中重新引发异常的概念。