用于解决问题的存根工厂 [英] Stubbing factory being used in resolve

查看:61
本文介绍了用于解决问题的存根工厂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对控制器中的状态进行单元测试.我想做的是将我的items工厂存根,因为我有单独的覆盖该功能的单元测试.我很难让$injector实际注入工厂,但似乎让$provider知道我想在实例化控制器时使用我的假物品对象.作为免责声明,我是angular的新手,如果我的代码看起来很糟糕,我希望提供一些建议.

I'm trying to unit test my states in an controller. What I want to do is stub out my items factory, since I have separate unit tests that cover that functionality. I'm having a hard time getting the $injector to actually inject the factory, but it seems like I'm letting the $provider know that I want to use my fake items object when it instantiates the controller. As a disclaimer I'm brand new to angular and would love some advice if my code looks bad.

当前,当我运行测试时,我收到消息:

Currently when I run the test I get the message:

Error: Unexpected request: GET /home.html
    No more request expected
        at $httpBackend (node_modules/angular-mocks/angular-mocks.js:1418:9)
        at n (node_modules/angular/angular.min.js:99:53)
        at node_modules/angular/angular.min.js:96:262
        at node_modules/angular/angular.min.js:131:20
        at m.$eval (node_modules/angular/angular.min.js:145:347)
        at m.$digest (node_modules/angular/angular.min.js:142:420)
        at Object.<anonymous> (spec/states/homeSpec.js:29:16)

看来我的模拟物品工厂没有被注入测试.在我想在项目工厂中存根的方法中放置console.log行时,我看到该行被调用.

It appears that my mocked items factory isn't being injected into the test. When I place a console.log line in the method I want to stub in the items factory I see that line being invoked.

我要测试的代码如下:

angular.module('todo', ['ui.router'])
// this is the factory i want to stub out...
.factory('items', ['$http', function($http){
  var itemsFactory = {};
  itemsFactory.getAll = function() {
    // ...specifically this method
  };
  return itemsFactory;
}])
.controller('TodoCtrl', ['$scope', 'items', function($scope, items) {
  // Do things
}])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
  $stateProvider
    .state('home', {
      url: '/home',
      templateUrl: '/home.html',
      controller: 'TodoCtrl',
      resolve: {
        items: ['items', function(items){
          // this is the invocation that i want to use my stubbed method
          return items.getAll();
        }]
      }
    });

  $urlRouterProvider.otherwise('home');
}]);

我的测试如下:

describe('home state', function() {

  var $rootScope, $state, $injector, state = 'home';
  var getAllStub = sinon.stub();
  var items = {
    getAll: getAllStub
  };

  beforeEach(function() {
    module('todo', function($provide) {
      $provide.value('items', items);
    });

    inject(function(_$rootScope_, _$state_, _$injector_) {
      $rootScope = _$rootScope_;
      $state = _$state_;
      $injector = _$injector_;
    });
  });

  it('should resolve items', function() {
    getAllStub.returns('getAll');

    $state.go(state);
    $rootScope.$digest();
    expect($state.current.name).toBe(state);

    expect($injector.invoke($state.current.resolve.items)).toBe('findAll');
  });
});

提前感谢您的帮助!

推荐答案

在单元测试中允许使用真正的路由器是一个坏主意,因为它破坏了隔离并增加了更多的活动部件.我个人认为$stateProvider等存根是更好的测试策略.

Allowing real router in unit tests is a bad idea because it breaks the isolation and adds more moving parts. I personally consider $stateProvider, etc. stubs a better testing strategy.

顺序在配置块中很重要,应该在将服务提供者注入其他模块之前对其进行模拟.如果原始模块具有覆盖模拟服务提供者的config块,则应将其存根:

The order matters in config blocks, service providers should be mocked before they will be injected in other modules. If the original modules have config blocks that override mocked service providers, the modules should be stubbed:

  beforeAll(function () {
    angular.module('ui.router', []);
  });

  beforeEach(function () {
    var $stateProviderMock = {
      state: sinon.stub().returnsThis()
    };

    module(function($provide) {
      $provide.constant('$stateProvider', $stateProviderMock);
    });
    module('todo');
  });

您只需要确保使用预期的配置对象作为参数调用$stateProvider.state:

You just need to make sure that $stateProvider.state is called with expected configuration objects an arguments:

  it('should define home state', function () {
    expect($stateProviderMock.state.callCount).to.equal(1);

    let [homeStateName, homeStateObj] = $stateProviderMock.state.getCall(0).args;

    expect(homeStateName).to.equal('home');
    expect(homeState).to.be.an('object');

    expect(homeState.resolve).to.be.an('object');
    expect(homeState.resolve.items).to.be.an('array');

    let resolvedItems = $injector.invoke(homeState.resolve.items);
    expect(items.getAll).to.have.been.calledOnce;
    expect(resolvedItems).to.equal('getAll');

    ...
  });

这篇关于用于解决问题的存根工厂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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