正在解决的存根工厂 [英] Stubbing factory being used in resolve

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

问题描述

我正在尝试在控制器中对我的状态进行单元测试.我想要做的是剔除我的 items 工厂,因为我有单独的单元测试来涵盖该功能.我很难让 $injector 实际注入工厂,但似乎我让 $provider 知道我想使用我的假货items 对象在实例化控制器时.作为免责声明,我是 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天全站免登陆