AngularJS测试控制器包含routeChangeSuccess [英] AngularJS Test Controller Containing routeChangeSuccess

查看:126
本文介绍了AngularJS测试控制器包含routeChangeSuccess的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建单元测试来测试导航列表控制器,和我在与创建测试的问题。

下面是code的控制器。

  navListModule.controller('NavListCtrl',['$范围,NavList',
    功能($范围,NavList){
        $范围。在('$ routeChangeSuccess'$,功能(事件的RouteData){
            VAR的stationID = routeData.params.stationId;            如果((的stationID == NULL)及!&安培;!(==的stationID未定义)){
                $ scope.stationId =的stationID;
                VAR navList = NavList;
                $ scope.menuOptions = navList.getMenuOptions(的stationID);
            }
        });
    }
]);

下面是我想出到目前为止,在我的单元测试。

 使用严格的;描述(单元测试navListModule',函数(){    VAR范围,CTRL位置;    描述(测试NavListCtrl',函数(){        beforeEach(模块('shipApp.navListModule'));        //模拟NavListService用于测试目的
        VAR mockNavListService = {
            getMenuOptions:功能(的stationID){
                //设置默认的菜单选项
                VAR menuOptions = [
                    {
                        名称:警报
                        ,PAGEURL:警报
                    }
                    {
                        名称:报告
                        ,PAGEURL:报告
                    }
                    {
                        名称:运行密奏
                        ,PAGEURL:清仓
                    }
                ];                //添加管理菜单选项,如果设置的stationID管理员
                如果(stationId.toUpperCase()=='Admin'.toUpperCase()){
                    menuOptions.push(
                        {
                            名称:管理
                            ,PAGEURL:管理员
                        }
                    );
                }                返回menuOptions;
            }
        };        beforeEach(注(函数($ rootScope,$控制器,$位置){
            范围= $ rootScope $新的()。
            CTRL = $控制器('NavListCtrl',{$适用范围:适用范围,NavList:mockNavListService});
            位置= $位置;
        }));        它('应该期望,如果没有的stationID在路由参数定义的stationID是未定义',函数(){
            期待(scope.stationId).toBeUndefined();
        });        它('应该期望范围。$上不要被所谓如果路径没有变化'),功能({
            spyOn(范围,'$上');
            预计.not.toHaveBeenCalled()($的范围。);
        });        它('应该期望范围。$上进行对路由变化称为',函数(){
            spyOn(范围,'$上');
            。在范围$('$ routeChangeSuccess',函数(事件的RouteData){});
            预计.toHaveBeenCalled()($的范围。);
        });        它('应该期望在路由参数中定义的stationID如果路线#/:的stationID /路径,注入(函数($ routeParams){
            location.path('/管理/警报');
            VAR locationElements = location.path()子(location.path()的indexOf('/')+ 1)。.split('/')。
            变种的stationID = locationElements [0];
            $ routeParams.stationId =的stationID;
            期待($ routeParams.stationId).toEqual(管理员);
        }));        它('应该期望时getMenuOptions函数被调用返回menuOptions阵',函数(){
            VAR的stationID ='管理员';
            VAR menuOptions = NavListCtrl.getMenuOptions(的stationID);
        });    });});

我刚学角度,所以我不知道如果我正确设置我的测试。我应该创建测试,以确保控制器逻辑不会发生,直到$ routeChangeSuccess事件发生后?如果是这样,我怎么写这样的测试?此外,什么是测试要求getMenuOptions(最后的测试)的正确方法?请让我知道,以测试该控制器的正确方法。

在此先感谢,
肖恩

玩弄一些测试和jvandemo一些帮助后,这里是我想出了为单元测试控制器,以及底层服务。请让我知道,如果我做错了什么。

 使用严格的;描述(单元测试navListModule',函数(){    beforeEach(模块('shipApp.navListModule'));    / ***** *****控制器/    描述(测试NavListCtrl',函数(){        VAR CTRL,范围,NavList,$ httpBackend,$位置,$路径,$ routeParams;        //嘲笑路由的HTTP后台
        beforeEach(模块(函数(){
            返回功能(_ $ httpBackend_){
                $ httpBackend = _ $ httpBackend_;
                $ httpBackend.when('GET','意见/警报/ alerts.html文件)响应('警报')。
                $ httpBackend.when('GET','意见/警报/ reports.html')响应(报告)。
                $ httpBackend.when('GET','意见/警报/ closeOuts.html')响应('清仓')。
                $ httpBackend.when('GET','意见/警报/ admin.html')响应(管理员)。
                $ httpBackend.when('GET','意见/共享/的error.html)响应('未找到')。
            };
        }));        //加$ routeProvider模拟
        beforeEach(模块(函数($ routeProvider){
            $ routeProvider.when('/:的stationID /警报',{
                templateUrl:意见/警报/ alerts.html文件',
                控制器:'AlertsCtrl
            });
            $ routeProvider.when('/:的stationID /报告',{
                templateUrl:意见/报告/ reports.html',
                控制器:'ReportsCtrl
            });
            $ routeProvider.when('/:的stationID /清仓',{
                templateUrl:意见/清仓/ closeOuts.html',
                控制器:'CloseOutsCtrl
            });
            $ routeProvider.when('/:的stationID /管理员',{
                templateUrl:意见/管理/ admin.html',
                控制器:'AdminCtrl
            });
            $ routeProvider.when('/ 404',{
                templateUrl:查看/共享/的error.html,
                控制器:'ErrorCtrl
            });
            $ routeProvider.when('/',{
                redirectTo:'/ MasterPl /警报
            });
            $ routeProvider.when('/:的stationID',{
                redirectTo:'/:的stationID /警报
            });
            $ routeProvider.when(':的stationID',{
                redirectTo:'/:的stationID /警报
            });
            $ routeProvider.when('',{
                redirectTo:'/ MasterPl /警报
            });
            $ routeProvider.otherwise({
                redirectTo:'/ 404'
            });
        }));        beforeEach(注(函数($ rootScope,$控制器_ $位置指定:,_ $ route_,_ $ routeParams_){
            //模拟NavList服务
            VAR mockNavListService = {
                getMenuOptions:功能(的stationID){
                    //设置默认的菜单选项
                    VAR menuOptions = [
                        {
                            名称:警报
                            ,PAGEURL:警报
                        }
                        {
                            名称:报告
                            ,PAGEURL:报告
                        }
                        {
                            名称:运行密奏
                            ,PAGEURL:清仓
                        }
                    ];                    //添加管理菜单选项,如果设置的stationID管理员
                    如果(stationId.toUpperCase()=='Admin'.toUpperCase()){
                        menuOptions.push(
                            {
                                名称:管理
                                ,PAGEURL:管理员
                            }
                        );
                    }                    返回menuOptions;
                }
            };
            NavList = mockNavListService;
            范围= $ rootScope $新的()。
            $位置= _ $位置指定:;
            $路线= _ $ route_;
            $ routeParams = _ $ routeParams_;
            CTRL = $控制器('NavListCtrl',{$适用范围:适用范围,$ routeParams:$ routeParams,NavList:NavList});
        }));        它('应该期望,如果没有的stationID在路由参数定义的stationID和menuOptions是未定义',函数(){
            期待(scope.stationId).toBeUndefined();
            期待(scope.menuOptions).toBeUndefined();
        });        它('应该期望范围。$上不要被所谓如果路径没有变化'),功能({
            spyOn(范围,'$上');
            预计.not.toHaveBeenCalled()($的范围。);
        });        它('应该期望范围。$上进行对路由变化称为',函数(){
            spyOn(范围,'$上');
            。在范围$('$ routeChangeSuccess',函数(事件的RouteData){});
            预计.toHaveBeenCalled()($的范围。);
        });        它('不应$ routeChangeSuccess前解析$ routeParameters',函数(){
            $ location.path('/管理/警报');
            。范围$适用();
            期待(scope.stationId).toBeUndefined();
        });        它('应该期望$ routeChangeSuccess被解雇的位置/的stationID /路径之后范围值来设置',函数(){
            $ location.path('/管理/警报');
            。范围$适用();
            $ httpBackend.flush();
            期待(scope.stationId).toEqual(管理员);
            期待(scope.menuOptions).not.toBeUndefined();
        });        它('应该期望NavList.getMenuOptions(),以$ routeChangeSuccess被解雇的位置/的stationID /路径后,被称为',函数(){
            spyOn(NavList,'getMenuOptions')andCallThrough()。
            $ location.path('/管理/警报');
            。范围$适用();
            $ httpBackend.flush();
            期待(NavList.getMenuOptions).toHaveBeenCalled();
            期待(scope.menuOptions.length).not.toBe(0);
        });    });
    /***** 服务 *****/    描述(测试NavList服务',函数(){        VAR范围,NavList;        beforeEach(注(函数($ rootScope,_NavList_){
            范围= $ rootScope $新的()。
            NavList = _NavList_;
        }));        它('应该期望时getMenuOptions函数被调用返回menuOptions阵',函数(){
            VAR的stationID ='管理员';
            VAR menuOptions = NavList.getMenuOptions(的stationID);
            期待(menu​​Options.length).not.toBe(0);
        });        它('应该期望管理菜单选项,以在menuOptions如果是的stationID管理,功能(){
            VAR的stationID ='管理员';
            VAR menuOptions = NavList.getMenuOptions(的stationID);
            VAR hasAdminOption = FALSE;
            对于(VAR I = 0; I< menuOptions.length;我++){
                如果(menu​​Options [I] .name.toUpperCase()=='Admin'.toUpperCase()){
                    hasAdminOption = TRUE;
                    打破;
                }
            }
            期待(hasAdminOption).toBe(真);
        });        它('不应该期望管理员菜单选项是在menuOptions如果stationID且没有管理,功能(){
            VAR的stationID ='MasterPl';
            VAR menuOptions = NavList.getMenuOptions(的stationID);
            VAR hasAdminOption = FALSE;
            对于(VAR I = 0; I< menuOptions.length;我++){
                如果(menu​​Options [I] .name.toUpperCase()=='Admin'.toUpperCase()){
                    hasAdminOption = TRUE;
                    打破;
                }
            }
            期待(hasAdminOption).toBe(假);
        });    });});


解决方案

您在这儿在测试中做的非常出色了。我假设你的测试(除了最后一次测试)正常运行和将分别回答您的两个问题:


  1. $ routeChangeSuccess :有没有必要为你测试的核心AngularJS功能。当你依赖于 $ routeChangeSuccess 来在某一时刻运行code,它是AngularJS团队的责任和他们的测试套件,以确保 $ routeChangeSuccess 正常工作。


  2. getMenuOptions():因为这种方法是要注入服务的一部分,您可以创建一个独立的单元测试,测试的 NavList 服务和上次测试移动到该套件。既然你是单元测试,这是一个很好的做法,创建一个单独的测试套件为每个组件(控制器,服务等),让事情变得良好的组织和紧凑。


希望帮助!

I am trying to create unit tests to test a navigation list controller, and I'm having issues with creating the tests.

Here is the code for the controller.

navListModule.controller('NavListCtrl', ['$scope', 'NavList',
    function ($scope, NavList) {
        $scope.$on('$routeChangeSuccess', function (event, routeData) {
            var stationId = routeData.params.stationId;

            if ((stationId !== null) && (stationId !== undefined)) {
                $scope.stationId = stationId;
                var navList = NavList;
                $scope.menuOptions = navList.getMenuOptions(stationId);
            }
        });
    }
]);

Here is what I've come up with so far in my unit tests.

'use strict';

describe('unit testing navListModule', function () {

    var scope, ctrl, location;

    describe('test NavListCtrl', function () {

        beforeEach(module('shipApp.navListModule'));

        // mock NavListService for testing purposes
        var mockNavListService = {
            getMenuOptions: function (stationId) {
                // set default menu options
                var menuOptions = [
                    {
                        name: "Alerts"
                        , pageURL: "alerts"
                    }
                    , {
                        name: "Reports"
                        , pageURL: "reports"
                    }
                    , {
                        name: "Run Close Outs"
                        , pageURL: "closeOuts"
                    }
                ];

                // add admin menu option if stationId set to Admin
                if (stationId.toUpperCase() == 'Admin'.toUpperCase()) {
                    menuOptions.push(
                        {
                            name: "Admin"
                            , pageURL: "admin"
                        }
                    );
                }

                return menuOptions;
            }
        };

        beforeEach(inject(function ($rootScope, $controller, $location) {
            scope = $rootScope.$new();
            ctrl = $controller('NavListCtrl', { $scope: scope, NavList: mockNavListService });
            location = $location;
        }));

        it('should expect stationId to be undefined if stationId not defined in route parameters', function () {
            expect(scope.stationId).toBeUndefined();
        });

        it('should expect scope.$on not to be called if no change in route', function () {
            spyOn(scope, '$on');
            expect(scope.$on).not.toHaveBeenCalled();
        });

        it('should expect scope.$on to be called on change in route', function () {
            spyOn(scope, '$on');
            scope.$on('$routeChangeSuccess', function (event, routeData) {});
            expect(scope.$on).toHaveBeenCalled();
        });

        it('should expect stationId to be defined in route parameters if route is #/:stationId/path', inject(function ($routeParams) {
            location.path('/Admin/alerts');
            var locationElements = location.path().substring(location.path().indexOf('/') + 1).split('/');
            var stationId = locationElements[0];
            $routeParams.stationId = stationId;
            expect($routeParams.stationId).toEqual('Admin');
        }));

        it('should expect menuOptions array to be returned when getMenuOptions function is called', function () {
            var stationId = 'Admin';
            var menuOptions = NavListCtrl.getMenuOptions(stationId);
        });

    });

});

I'm just learning Angular, so I'm not sure if I'm setting up my tests properly. Should I create tests to ensure that the controller logic does not take place until after the $routeChangeSuccess event occurs? If so, how do I write such a test? Also, what is the proper way to test the call for getMenuOptions (last test)? Please let me know the proper way to test this controller.

Thanks in advance, Sean

After playing around with some testing and some help from jvandemo, here is what I have come up with for the unit tests for the controller, as well as the underlying service. Please let me know if I am doing something wrong.

'use strict';

describe('unit testing navListModule', function () {

    beforeEach(module('shipApp.navListModule'));

    /***** Controllers *****/

    describe('test NavListCtrl', function () {

        var ctrl, scope, NavList, $httpBackend, $location, $route, $routeParams;

        // mock the http backend for routing
        beforeEach(module(function() {
            return function(_$httpBackend_) {
                $httpBackend = _$httpBackend_;
                $httpBackend.when('GET', 'views/alerts/alerts.html').respond('alerts');
                $httpBackend.when('GET', 'views/alerts/reports.html').respond('reports');
                $httpBackend.when('GET', 'views/alerts/closeOuts.html').respond('closeOuts');
                $httpBackend.when('GET', 'views/alerts/admin.html').respond('admin');
                $httpBackend.when('GET', 'views/shared/error.html').respond('not found');
            };
        }));

        // add $routeProvider mock
        beforeEach(module(function ($routeProvider) {
            $routeProvider.when('/:stationId/alerts', {
                templateUrl : 'views/alerts/alerts.html',
                controller : 'AlertsCtrl'
            });
            $routeProvider.when('/:stationId/reports', {
                templateUrl : 'views/reports/reports.html',
                controller : 'ReportsCtrl'
            });
            $routeProvider.when('/:stationId/closeOuts', {
                templateUrl : 'views/closeOuts/closeOuts.html',
                controller : 'CloseOutsCtrl'
            });
            $routeProvider.when('/:stationId/admin', {
                templateUrl : 'views/admin/admin.html',
                controller : 'AdminCtrl'
            });
            $routeProvider.when('/404', {
                templateUrl : 'views/shared/error.html',
                controller : 'ErrorCtrl'
            });
            $routeProvider.when('/', {
                redirectTo : '/MasterPl/alerts'
            });
            $routeProvider.when('/:stationId', {
                redirectTo : '/:stationId/alerts'
            });
            $routeProvider.when(':stationId', {
                redirectTo : '/:stationId/alerts'
            });
            $routeProvider.when('', {
                redirectTo : '/MasterPl/alerts'
            });
            $routeProvider.otherwise({
                redirectTo: '/404'
            });
        }));

        beforeEach(inject(function ($rootScope, $controller, _$location_, _$route_, _$routeParams_) {
            // mock NavList service
            var mockNavListService = {
                getMenuOptions: function (stationId) {
                    // set default menu options
                    var menuOptions = [
                        {
                            name: "Alerts"
                            , pageURL: "alerts"
                        }
                        , {
                            name: "Reports"
                            , pageURL: "reports"
                        }
                        , {
                            name: "Run Close Outs"
                            , pageURL: "closeOuts"
                        }
                    ];

                    // add admin menu option if stationId set to Admin
                    if (stationId.toUpperCase() == 'Admin'.toUpperCase()) {
                        menuOptions.push(
                            {
                                name: "Admin"
                                , pageURL: "admin"
                            }
                        );
                    }

                    return menuOptions;
                }
            };


            NavList = mockNavListService;
            scope = $rootScope.$new();
            $location = _$location_;
            $route = _$route_;
            $routeParams = _$routeParams_;
            ctrl = $controller('NavListCtrl', { $scope: scope, $routeParams: $routeParams, NavList: NavList });
        }));

        it('should expect stationId and menuOptions to be undefined if stationId not defined in route parameters', function () {
            expect(scope.stationId).toBeUndefined();
            expect(scope.menuOptions).toBeUndefined();
        });

        it('should expect scope.$on not to be called if no change in route', function () {
            spyOn(scope, '$on');
            expect(scope.$on).not.toHaveBeenCalled();
        });

        it('should expect scope.$on to be called on change in route', function () {
            spyOn(scope, '$on');
            scope.$on('$routeChangeSuccess', function (event, routeData) {});
            expect(scope.$on).toHaveBeenCalled();
        });

        it('should not parse $routeParameters before $routeChangeSuccess', function () {
            $location.path('/Admin/alerts');
            scope.$apply();
            expect(scope.stationId).toBeUndefined();
        });

        it('should expect scope values to be set after $routeChangeSuccess is fired for location /stationId/path', function () {
            $location.path('/Admin/alerts');
            scope.$apply();
            $httpBackend.flush();
            expect(scope.stationId).toEqual('Admin');
            expect(scope.menuOptions).not.toBeUndefined();
        });

        it('should expect NavList.getMenuOptions() to have been called after $routeChangeSuccess is fired for location /stationId/path', function () {
            spyOn(NavList, 'getMenuOptions').andCallThrough();
            $location.path('/Admin/alerts');
            scope.$apply();
            $httpBackend.flush();
            expect(NavList.getMenuOptions).toHaveBeenCalled();
            expect(scope.menuOptions.length).not.toBe(0);
        });

    });


    /***** Services *****/

    describe('test NavList service', function () {

        var scope, NavList;

        beforeEach(inject(function ($rootScope, _NavList_) {
            scope = $rootScope.$new();
            NavList = _NavList_;
        }));

        it('should expect menuOptions array to be returned when getMenuOptions function is called', function () {
            var stationId = 'Admin';
            var menuOptions = NavList.getMenuOptions(stationId);
            expect(menuOptions.length).not.toBe(0);
        });

        it('should expect admin menu option to be in menuOptions if stationId is Admin', function () {
            var stationId = 'Admin';
            var menuOptions = NavList.getMenuOptions(stationId);
            var hasAdminOption = false;
            for (var i = 0; i < menuOptions.length; i++) {
                if (menuOptions[i].name.toUpperCase() == 'Admin'.toUpperCase()) {
                    hasAdminOption = true;
                    break;
                }
            }
            expect(hasAdminOption).toBe(true);
        });

        it('should not expect admin menu option to be in menuOptions if stationId is not Admin', function () {
            var stationId = 'MasterPl';
            var menuOptions = NavList.getMenuOptions(stationId);
            var hasAdminOption = false;
            for (var i = 0; i < menuOptions.length; i++) {
                if (menuOptions[i].name.toUpperCase() == 'Admin'.toUpperCase()) {
                    hasAdminOption = true;
                    break;
                }
            }
            expect(hasAdminOption).toBe(false);
        });

    });

});

解决方案

You're doing a great job here in your tests already. I assume your tests are running correctly (apart from the last test) and will answer your 2 questions separately:

  1. $routeChangeSuccess: there is no need for you to test core AngularJS functionality. When you depend on $routeChangeSuccess to run your code at a certain moment, it is the responsibility of the AngularJS team and their test suite to ensure that $routeChangeSuccess works correctly.

  2. getMenuOptions(): since this method is part of a service you are injecting, you can create a separate unit test that tests the NavList service and move the last test to that suite. Since you are unit testing, it is a good practice to create a separate test suite for each component (controller, service, etc) to keep things well organized and compact.

Hope that helps!

这篇关于AngularJS测试控制器包含routeChangeSuccess的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆