控制器函数`上的TypeError

时间:2014-07-30 12:38:44

标签: angularjs jasmine

我在我的控制器上运行一个测试,以确定它是否已正确定义,但我在控制器对象上持续TypeError: undefined。这是完整的错误:

Search Controller
  should have the controller defined <<< FAILURE!
* TypeError: 'undefined' is not an object (evaluating 'myMenuDataLoad.then')
* Expected undefined to be defined.

这是要测试的控制器:

myAppControllers.controller('VisibilitySearchController', ['$scope', 'headerService', 'menuService', 'navigationService', function($scope, headerService, menuService, navigationService ){

headerService.setTitle('My title');

var myMenuDataLoad = menuService.loadData('partials/common/components/menu-bar/json/menu-bar.json');

myMenuDataLoad.then(function(dataResult){
    menuService.setData(dataResult.data);
});

var myNavDataLoad = navigationService.loadData('partials/common/components/navigation-bar/json/navigation-bar.json');
myNavDataLoad.then(function(dataResult){
    navigationService.setData(dataResult.data);
});


}]);

我已经通过在其参数中传递所需的一切来初始化控制器,即scopeheaderServicemenuServicenavigationService - 我使用模拟这些服务jasmine.createSpyObj方法并传入所有相关方法(控制器上使用的方法):

// Mock our services
beforeEach(function() {

    // Methods are accepted as the 2nd second parameter
    headerService = jasmine.createSpyObj('headerService', ['setTitle']);
    module(function($provide) {
        $provide.value('headerService', headerService);
    });

    menuService = jasmine.createSpyObj('menuService', ['loadData', 'setData']);
    module(function($provide) {
        $provide.value('menuService', menuService);
    });

    navigationService = jasmine.createSpyObj('navigationService', ['loadData', 'setData']);
    module(function($provide) {
        $provide.value('navigationService', navigationService);
    });
});

控制器的实际初始化发生在这里:

beforeEach(inject(function($rootScope, $injector, $controller, _headerService_, _menuService_, _navigationService_) {

    scope = $rootScope.$new();

    // Instantiate the controller
    searchController = $controller('VisibilitySearchController', {
        $scope : scope,
        headerService : headerService,
        menuService : menuService,
        navigationService : navigationService
    });
}));

那我在这里做错了什么?为什么测试(见下文)没有通过?

it("should have the controller defined", function() {
    expect(searchController).toBeDefined();
});

我是否正确地嘲笑了这些服务?需要对本地控制器变量执行哪些操作才能正确初始化它们以及它们使用的方法?

谢谢!


更新

我已经进一步研究了这一点,但不幸的是仍然收到了同样的未定义错误。当您创建服务的模拟对象时,您是否必须提供该服务及其使用的所有依赖项和方法?例如:

 menuService = jasmine.createSpyObj('menuService', ['$parse','$q', 'dataService', 'loadData', 'then']);
    module(function($provide) {
        $provide.value('menuService', menuService);
    });

这里当我创建模拟对象时,我为它提供了它所期望的所有依赖项,另外我添加了两个我在控制器中使用的函数。 那么我该如何在模拟对象中模拟一个函数呢?我试过这个,但我仍然得到同样的错误:

menuService.loadData = jasmine.createSpy( 'loadData()' ).andReturn( data );

1 个答案:

答案 0 :(得分:1)

正如评论中所提到的,menuService.loadData()将始终返回undefined,因此评估表达式myMenuDataLoad.then将始终失败,如错误中所述。您必须做的是提供menuService.loadData的实现,它将返回一个承诺。你可以像你想要调用这些方法一样进行模拟,但是你不依赖于它的任何返回值。如果您需要使用该方法返回某些内容,则可以通过以下方式定义menuService

var menuService = {
    loadData: function() {  
        var deferred = $q.defer();      
        var data = []; //put any data you need here to be returned within the promise       

        deferred.resolve{data);             
        return deferred.promise;    
    }
}

module(function($provide) {
        $provide.value('menuService', menuService);
    });

您需要$q的实例,您可以在inject来电中使用[{1}},$rootScope等等。

如果您想监视$injector功能,可以这样做:

menuService.load

这将保留你的方法的模拟实现,但仍然允许你断言它被调用等。我认为你不需要它。