【问题标题】:angular-ui/bootstrap: Testing a controller that uses a dialogangular-ui/bootstrap:测试使用对话框的控制器
【发布时间】:2013-03-07 13:49:33
【问题描述】:

我有一个控制器,它使用来自 angular-ui/bootstrap 的对话框:

   function ClientFeatureController($dialog, $scope, ClientFeature, Country, FeatureService) {

        //Get list of client features for selected client (that is set in ClientController)
        $scope.clientFeatures = ClientFeature.query({clientId: $scope.selected.client.id}, function () {
            console.log('getting clientfeatures for clientid: ' + $scope.selected.client.id);
            console.log($scope.clientFeatures);
        });

        //Selected ClientFeature
        $scope.selectedClientFeature = {};

        /**
         * Edit selected clientFeature.
         * @param clientFeature
         */
        $scope.editClientFeature = function (clientFeature) {
            //set selectedClientFeature for data binding
            $scope.selectedClientFeature = clientFeature;

            var dialogOpts = {
                templateUrl: 'partials/clients/dialogs/clientfeature-edit.html',
                controller: 'EditClientFeatureController',
                resolve: {selectedClientFeature: function () {
                    return clientFeature;
                } }
            };
            //open dialog box
            $dialog.dialog(dialogOpts).open().then(function (result) {
                if (result) {
                    $scope.selectedClientFeature = result;
                    $scope.selectedClientFeature.$save({clientId: $scope.selectedClientFeature.client.id}, function (data, headers) {
                        console.log('saved.');
                    }, null);
                }
            });
        };
    });

我对测试几乎完全陌生,并认为我可能需要测试两件事:

  1. 调用 $scope.editClientFeature() 时会打开一个对话框
  2. 在对话框关闭后成功调用 $save 并返回“结果”

我真正搞砸的测试现在看起来像这样:

describe('ClientFeatureController', function () {
    var scope, $dialog, provider;

    beforeEach(function () {
            inject(function ($controller, $httpBackend, $rootScope, _$dialog_) {
            scope = $rootScope;
            $dialog = _$dialog_;

            //mock client
            scope.selected = {};
            scope.selected.client = {
                id: 23805
            };

            $httpBackend.whenGET('http://localhost:3001/client/' + scope.selected.client.id + '/clientfeatures').respond(mockClientFeatures);
            $controller('ClientFeatureController', {$scope: scope});
            $httpBackend.flush();
        });
    });


    it('should inject dialog service from angular-ui-bootstrap module', function () {
        expect($dialog).toBeDefined();
        console.log($dialog); //{}
    });

    var dialog;

    var createDialog = function (opts) {
        dialog = $dialog.dialog(opts);
    };

    describe('when editing a clientfeature', function () {
        createDialog({});
        console.log(dialog); //undefined
//        var res;
//        var d;
//        beforeEach(function () {
//            var dialogOpts = {
//                template: '<div>dummy template</div>'
//            };
//            console.log(dialog);
//            d = $dialog.dialog(dialogOpts);
//            d.open();
//        });
//
//        it('should open a dialog when editing a client feature', function () {
//            expect(d.isOpen()).toBe(true);
//        });
    });

});

现在的直接问题是我无法创建/打开对话框。我收到以下错误:

Chrome 25.0 (Mac) ClientFeatureController when editing a clientfeature encountered a declaration exception FAILED
    TypeError: Cannot call method 'dialog' of undefined

如果有人已经为类似的用例编写了测试并且可以为我提供一个示例,那就太好了,因为我很迷茫。

谢谢, 肖恩

【问题讨论】:

    标签: javascript testing angularjs jasmine angular-ui


    【解决方案1】:

    直到现在,我一直在为同样的问题苦苦挣扎,在浏览了 github 存储库之后,我找到了对话测试并将其用作起点:

    var $dialog,$scope,$httpBackend;
      beforeEach(module('ui.bootstrap.dialog'));
      beforeEach(function(){
        inject(function (_$dialog_, _$httpBackend_, $controller){
          $dialog = _$dialog_;
          $httpBackend = _$httpBackend_;
          $httpBackend.expectGET('/appServer/list')
            .respond([{
                id:1,
                name:'test1'
              },
              {
                id:2,
                name:'test2'
              },
              {
                id:3,
                name:'test3'
              }]);
    
    
          //setup controller scope
          scope = {};
          ServerCtrl = $controller('ServerCtrl', {
            $scope: scope,
            $dialog:$dialog
          });
        });
      });
    

    【讨论】:

    • 我从您的帖子中意识到我忘记在 beforeEach 中包含“ui.bootstrap”模块。谢谢!
    【解决方案2】:

    我也更喜欢适当的模拟。当它不可用时,我会修补服务

    对此进行测试:

    $dialog.messageBox(title, msg, btns)
       .open()
       .then(function (result) {
           if (result == 'ok') {
                // block executed if user click OK
           }
    });
    

    你可以像这样修补 $dialog:

    $dialog.messageBox = function (title, msg, btns) {
        return {
            open: function () {
                return {
                     then: function (callback) {
                          callback('ok'); // 'ok' will be set to param result
                     }
                 }
            }
        }
     };
    

    【讨论】:

      【解决方案3】:

      我个人尝试模拟所有服务。如果 ui-bootstrap 项目没有提供 $dialog 模拟,你应该在那里打开一个 bug 票并要求他们提供一个。然而,创建一个同样容易。

      模拟服务应该有虚假的方法,除了返回承诺之外什么都不做。它还应该为您提供一种刷新所有异步方法的方法,以便更轻松地进行同步测试。

      【讨论】:

        【解决方案4】:

        我发现编写自己的对话框模拟是最清晰的。这是一个模拟对话框以模拟选择“是”的示例。

        被测代码

        .controller('AdminListingCtrl', function AdminListingController($scope, $dialog, houseRepository) {
            $scope.houses = houseRepository.query();
            $scope.remove = function (house) {
                var dlg = $dialog.messageBox('Delete house', 'Are you sure?', [
                    {label: 'Yep', result: 'yes'},
                    {label: 'Nope', result: 'no'}
                ]);
                dlg.open().then(function (result) {
                    if (result == 'yes') {
                        houseRepository.remove(house.id);
                        $scope.houses = houseRepository.query();
                    }
                });
            };
        }
        

        测试

            describe('when deleting a house', function () {
        
                var fakeDialog = {
                    open: function()
                    {
                        return {
                            then: function(callback) {
                                callback("yes");
                            }
                        };
                    }
                };
        
                beforeEach(inject(function($dialog) {
                    spyOn($dialog, 'messageBox').andReturn(fakeDialog);
                }));
        
                it('should call the remove method on the houseRepository', function () {
                    scope.remove({id: 99});
                    expect(houseRepository.remove).toHaveBeenCalledWith(99);
                });
        
                // etc
            });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多