0

我有一个这样的 AngularJS 控制器:

        app.controller('MyCtrl', function($scope, myFactory){  
            $scope.types = myFactory.getTypes();    
            $scope.model= {};    
            $scope.model.type = $scope.types[0].type;

    });
});

一切正常。

但我想在 Jasmine 中测试这个控制器。所以我像这样模拟myFactory和初始化myCtrl

 describe('Controllers: MyCtrl', function () {

        var MyCtrl, mockedFactory, scope;

        beforeEach(module('app.factories', function ($provide) {
            mockedFactory = {
                getTypes: function(){}
            };

            spyOn(mockedFactory, 'getTypes');
            $provide.value('myFactory', mockedFactory);
        }));

        beforeEach(module('app'));

        beforeEach(inject(function ($rootScope, $controller) {
            scope = $rootScope.$new();
            MyCtrl= $controller('MyCtrl', {
                $scope: scope
            });
        }));

        it('should call AccordTypeFactory.getAvailableTypes()', function () {
            scope.types;
            expect(mockedFactory.getTypes).toHaveBeenCalled();
        });

但我有一个逻辑错误:Cannot read property 0 of undefined

我理解这个错误;因为我模拟工厂我的控制器属性$scope.model.type它是未定义的,因为它使用工厂的结果$scope.types

我的问题很简单:我怎样才能使我的测试工作?

谢谢各位

4

2 回答 2

1
    beforeEach(module('app.factories', function ($provide) {
        mockedFactory = {
            getTypes: function(){ return [{}]; }
        };

        spyOn(mockedFactory, 'getTypes').andCallThrough();
        $provide.value('myFactory', mockedFactory);
    }));

如果我理解正确,您的问题是模拟不返回数组,而您的控制器希望其中始终至少有 1 个元素。您可以将模拟设置为返回一个包含元素的数组,然后andCallThrough()在间谍上使用以使其实际调用模拟。

如果您的工厂可能在应用程序运行时返回空数组,您可能需要在尝试访问之前检查该数组是否包含至少一个元素types[0]

于 2013-10-07T10:25:09.680 回答
0

我找到了比我认为的 andCallThrough 更好的解决方案。

这很简单,我只需在 spyOn 之后添加 andReturn 函数:

spyOn(mockedFactory, 'getTypes').andReturn([{type: 'MockType'}]);
于 2013-10-07T11:47:55.763 回答