单元测试承诺附加到AngularJS Scope

时间:2013-01-29 06:56:27

标签: javascript angularjs

AngularJS为您做的许多魔法之一是自动承诺解析,以便您可以编写如下代码:

function SomeCtrl($scope, Resource) {
    $scope.items = Resource.query();
}

然而,我通过JSON-RPC和ngResource使用函数的服务似乎不能很好地使用它。我不得不嘲笑后端做出适当的回应,但出于某种原因,我似乎无法弄清楚如何在控制器级别测试响应。

"use strict";

describe('controllers', function() {

    describe('LibraryCtrl', function() {
        var scope, ctrl;

        beforeEach(inject(function($rootScope, $controller) {

            JsonRpc.respondWith({ some : data });

            scope = $rootScope.$new();
            ctrl = $controller(LibraryCtrl, { $scope : scope }); 
            // controller does `$scope.items = RPCService.get()`
        }));

        it("should create a `items` model with data fetched via JSON-RPC", function() {
            // here's where I'm very confused
            // JsonRpc does $httpBackend.flush()
            JsonRpc.respond();

            // now I want to inspect the property on the controller
            expect(scope.items).toEqualData( { some : data } );
        }); 
    }); 

});

问题是,scope.items是一个承诺。该特定属性仍然是一个承诺,因为显然$digest()不解析承诺并重新附加返回值作为模型值。我不能做一个简单的平等断言。

我的解决方法是使用promise capture mock:

var result = {
    capture : function(v) { result.value = v; },
    value   : null,
};

然后试试这个:

scope.items.then(result.capture);
expect(result.value).toEqualData(...);

这确实有效(但感觉有些不对劲)。作为旁注(对于布朗尼点,这不是实际问题),用result.capture交换JsonRpc.respond()链会导致测试失败(result.value为空)。

以下是问题:测试作为范围模型的承诺的正确方法是什么?这是结果吗。我正在做的事情还好,还是有更好的方法去做?另外,我真的想知道为什么用响应刷新来反转promise附件导致响应无法解决和捕获......?

1 个答案:

答案 0 :(得分:2)

好问题。我的第一反应是你的控制器单元测试实际上是在这里测试ngResource。在我的控制器测试中,我模拟了资源:

mockResource = {query: jasmine.createSpy('query').andReturn([{id: 1, name: foo}])

module(function ($provide) {
   $provide.value('Resource', mockResource);

...

expect(mockResource.find).toHaveBeenCalled()
expect(scope.items)....

这允许您单独测试控制器。