【问题标题】:angularjs route unit testingangularjs路由单元测试
【发布时间】:2013-04-06 02:05:28
【问题描述】:

正如我们在http://docs.angularjs.org/tutorial/step_07 中看到的,

angular.module('phonecat', []).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
      when('/phones', {templateUrl: 'partials/phone-list.html',   controller: PhoneListCtrl}).
      when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
      otherwise({redirectTo: '/phones'});
}]);

路由测试建议采用e2e测试,

  it('should redirect index.html to index.html#/phones', function() {
    browser().navigateTo('../../app/index.html');
    expect(browser().location().url()).toBe('/phones');
  });

但是,我认为“$routeProvider”配置是使用单个函数 function($routeProvider) 完成的,我们应该能够在不涉及浏览器的情况下进行单元测试,因为我认为路由功能不需要浏览器 DOM。

例如,
当 url 为 /foo 时,templateUrl 必须为 /partials/foo.html 且控制器为 FooCtrl
当 url 为 /bar 时,templateUrl 必须为 /partials/bar.html 且控制器为 BarCtrl

它是一个简单的函数IMO,它也应该在一个简单的测试,一个单元测试中进行测试。

我用谷歌搜索并搜索了这个 $routeProvider 单元测试,但还没有运气。

我想我可能会从这里借一些代码,但还不能做到,https://github.com/angular/angular.js/blob/master/test/ng/routeSpec.js

【问题讨论】:

  • 两者都不够好?
  • 但是,人们不得不怀疑这是否会产生一个提供实际价值的单元测试;大多数路由配置就是这样,配置和单元测试可以归结为“/some/route 是否等于 /some/route?”
  • @fwielstra,是的,这种测试感觉就像double entry。再说一次,我发现大多数测试都有这种感觉。另一方面,我发现复式输入很有用。
  • 这里的答案对我有用。模拟 $httpBackend stackoverflow.com/questions/17963717/…

标签: angularjs unit-testing jasmine angularjs-routing


【解决方案1】:

结合前面的两个答案,如果您想将路由器作为一个成功路由到应有的位置(而不是控制器本身配置)的黑盒进行测试,无论路由可能是:

// assuming the usual inject beforeEach for $route etc.
var expected = {};
it('should call the right controller for /phones route', function () { 
    expected.controller = $route.routes['/phones'].controller;
    $location.path('/phones');
    $rootScope.$digest();
    expect($route.current.controller).toBe(expected.controller);
});

it('should redirect to redirectUrl from any other route', function () {
    expected.path = $route.routes[null].redirectTo;
    $location.path('/wherever-wrong');
    $rootScope.$digest();
    expect($location.path()).toBe(expected.path);
});

【讨论】:

    【解决方案2】:

    为什么不直接断言路由对象配置正确?

    it('should map routes to controllers', function() {
      module('phonecat');
    
      inject(function($route) {
    
        expect($route.routes['/phones'].controller).toBe('PhoneListCtrl');
        expect($route.routes['/phones'].templateUrl).
          toEqual('partials/phone-list.html');
    
        expect($route.routes['/phones/:phoneId'].templateUrl).
          toEqual('partials/phone-detail.html');
        expect($route.routes['/phones/:phoneId'].controller).
          toEqual('PhoneDetailCtrl');
    
        // otherwise redirect to
        expect($route.routes[null].redirectTo).toEqual('/phones')
      });
    });
    

    【讨论】:

    • 当我尝试测试路由器时,对于最后一个场景“expect($ route.routes[null].redirectTo).toEqual('/phones')"
    • 这对我来说似乎是一个非常无用的测试。并不是说别人提出的风格更好。
    • 这不会测试基于状态的路由是否可用/callabe。例如,这如何涵盖“我没有登录并尝试访问受限资源”的情况?
    • @AndreschSerj,OP 询问我如何对路线进行单元测试。您的评论将成为一个很好的系统测试。
    【解决方案3】:

    我认为您应该能够像这样测试 $routeProvider:

    angular.module('phonecat', []).
      config(['$routeProvider', function($routeProvider) {
      $routeProvider.
          when('/phones', {templateUrl: 'partials/phone-list.html',   controller: PhoneListCtrl}).
          when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
          otherwise({redirectTo: '/phones'});
    }]);
    
    
    it('should test routeProvider', function() {
      module('phonecat');
    
      inject(function($route, $location, $rootScope) {
    
        expect($route.current).toBeUndefined();
        $location.path('/phones/1');
        $rootScope.$digest();
    
        expect($route.current.templateUrl).toBe('partials/phone-detail.html');
        expect($route.current.controller).toBe(PhoneDetailCtrl);
    
        $location.path('/otherwise');
        $rootScope.$digest();
    
        expect($location.path()).toBe('/phones/');
        expect($route.current.templateUrl).toEqual('partials/phone-list.html');
        expect($route.current.controller).toBe(PhoneListCtrl);
    
      });
    }); 
    

    【讨论】:

    • 这是完美的。 $rootScope.$digest() 正是我所需要的。
    • 这不起作用,因为 Angular 想要触发一个 HttpBackend 调用以通过 Ajax 检索模板......虽然上面的解决方案(来自 zhon)有效!
    • 只需要添加正确的expectGET $httpBackend。这是我的例子plnkr.co/edit/j1o0iu?p=preview
    • 我认为这个解决方案更好,因为它也可以测试路由参数解析。除了使用 $httpBackend,您还可以使用以下内容加载模板:beforeEach(module('partials/browse-view.html'));
    猜你喜欢
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 2013-07-28
    • 2014-04-29
    • 2015-04-01
    • 1970-01-01
    • 2022-06-23
    • 2013-05-27
    相关资源
    最近更新 更多