【问题标题】:How can I test a controller with resolve properties in AngularJS?如何在 AngularJS 中测试具有解析属性的控制器?
【发布时间】:2013-02-25 15:49:58
【问题描述】:

如何测试具有解析属性的控制器? 它抛出一个错误:未知提供者:InitProvider,在测试期间,可以理解。 如何测试?

我使用路由配置中的 init 属性来加载数据并在控制器实例化时将其传递给控制器​​,因此在加载数据之前路由不会改变。

  $routeProvider
    .when('/topic/:topic_id/content/:content_id', {
      templateUrl: 'views/content.html',
      controller: 'ContentCtrl',
    resolve: {
      init: ContentCtrl.init
    }
    });

模式一开始就完全错误吗?

'use strict';

var ContentCtrl = ['$scope', '$location', '$routeParams', 'init', function ($scope, $location, $routeParams, init) {

    $scope.contents = init.contents;

  }];

ContentCtrl.init = ['$q', 'app_config', '$log', '$timeout', function ($q, app_config, $log, $timeout) {

    var defer = $q.defer();

    $log.log("ContentCtrl loading..");

    $timeout(function() {
        defer.resolve({contents: [
                                    {message: 'Hello!'}
                                  ]});

        $log.log("ContentCtrl loaded.");

    }, 2000);

    return defer.promise;
}];

angular.module('studentportalenApp').controller('ContentCtrl', ContentCtrl);

我想将整个控制器封装在 .controler('ContentCtrl', function() { ... }) 中,但还没有弄清楚如何正确完成以使 init 在路由配置中可用。

【问题讨论】:

  • 尝试将 ContentCtrl.init 转换为角度 service 并在需要时将该服务作为依赖项注入

标签: unit-testing angularjs jasmine


【解决方案1】:

在这里遇到同样的事情。我使用这里的方法解决了它:https://groups.google.com/forum/?fromgroups=#!topic/angular/LzXm-9nwkjY

基本上,我模拟了通常使用简单变量发送的数据,并将其添加到测试中的控制器中。在你的情况下,我认为它看起来像:

var initData = {
      contents: [{message: 'Hello!'}]
};
$controller("ContentCtrl", { $scope: ..., init: initData });

【讨论】:

    【解决方案2】:

    正如 charlietfl 所建议的,最终通过将一切都转换为服务来解决。

    例子:

    路线配置:

    //This helper injects a function with the service 
    //defined in the initMethod string and returns services.prepare()
    var interceptWith = function(initMethod) {
            return [initMethod, function(m) {
                        return m.prepare();
                    }];
    }
    
    $routeProvider        
        .when('/foobar/', {
            templateUrl: 'foobar.html',
            controller: 'FoobarCtrl',
            resolve: {
                init: interceptWith('FoobarCtrlInit')
            }
        });
    

    foobar 控制器定义:

    angular.module('fooApp').controller('FoobarCtrl', ['$scope', 'init', function ($scope, init) {              
                $scope.data = init.data;    
      }])
    .service('FoobarCtrlInit', ['$q', '$timeout', function ($q, $timeout) {
    
            var _prepare = function() {
    
                var deferred = $q.defer();
    
                //Fake async loading of data
                $timeout(function() {
                     deferred.resolve({data: ['A','B','C']});
                }, 1000);
    
    
    
    
                return deferred.promise; 
            }
    
            return {
                prepare: _prepare
            }
    }]);
    

    要对此进行测试,可以这样做:

    'use strict';
    
    describe('Controller: FoobarCtrl', function() {
    
      // load the controller's module
      beforeEach(module('fooApp'));
    
      var FoobarCtrl,
        scope;
    
      // Initialize the controller and a mock scope
      beforeEach(inject(function($controller) {
        scope = {};
        CourseCtrl = $controller('FoobarCtrl', {
          $scope: scope,
          init: {data: ['Testdata A', 'B', 'C']}
        });
      }));
    
      it('should attach a list of data to the scope', function() {
        expect(scope.data.length).toBe(3);
      });
    });
    

    【讨论】:

      【解决方案3】:

      在 $routeProvider 上使用解析时,我在 Karma 中遇到了同样的错误,我通过在 app.js 的单元测试中测试我的解析来修复它,如下所示:

      describe("myApp",  function() {
      
        beforeEach(module('myApp'));
      
        it('should resolve initial values for my Controller', inject(function( $route ) {
          expect($route.routes['/'].resolve.init).toBeDefined; //or whatever test you want
        }));
      });
      

      然后我只是在我的控制器的测试中模拟了这个值,就像在控制器的描述中一样:

      //mock out the resolved values to isolate controller code
        beforeEach(module(function($provide) {
          $provide.value('init', function() {
            return 'whatever data you need to mock';
          });
      

      【讨论】:

        【解决方案4】:

        对路由的解析值进行单元测试:

        var resolvedObject = $injector.invoke($route.current.$$route.resolve.testedObject);

        【讨论】:

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