在Jasmine中使用$ q的模拟角度工厂

时间:2015-06-23 22:08:00

标签: javascript angularjs jasmine

肯定以前曾经问过,但我找不到它。我需要模拟一个工厂,但模拟本身需要使用$ q,我最终会遇到关于在inject()之后调用module()的鸡蛋和鸡蛋情况。

我查看了这个question建议做一个spyOn,它适用于服务,因为它是一个单身,但我在函数上调用 new 我的工厂返回,每次都创建一个新的实例,这样就无法工作......

var app = angular.module('app', []);

app.factory('MyDependencyFactory', function() {
  return function() {
    this.doPromise = function () {
      var defer = $q.defer();
      //obviously more complicated.
      defer.resolve();
      return defer.promise;   
    }
  }
});

app.factory('MyConsumingFactory', function(MyDependencyFactory) {
 return function() {
   var dependency = new MyDependencyFactory();
   this.result;

   this.doSomething = function () {
     dependency.doPromise().then(
       function (data) {
         this.result = data;
       },
       function (error) {
         console.log(error);
       }
       );
   }
  }
});

茉莉花测试:

describe('MyConsumingFactory', function() {
  var MyConsumingFactory;

  beforeEach(function () {
    module('app');

    inject( function (_MyConsumingFactory_) {
      MyConsumingFactory = _MyConsumingFactory_;
    });

    inject( function ($q) {
      mockMyDependencyFactory = function () {
        this.doPromise = function (data) {
            var defer = $q.defer();
            defer.resolve('mock data');
          };
        };
    });

    module( function ($provide) {
      $provide.factory('MyDependencyFactory', mockMyDependencyFactory);
    });
  });

  it('works correctly', function () {
    MyConsumingFactory.doSomething();
    $rootScope.$apply();
    expect(MyConsumingFactory.result).toEqual('mock data');
  });

});

我需要使用我的mockMyDependencyFactory来使用$ q,所以我需要将它包装在 inject(函数(... )中,我需要在调用模块之前执行此操作(函数) ($ offer){... 当然给了我:

错误:注射器已经创建,无法注册模块!

关于我如何解决这个问题的任何建议?

或者如果你认为我的设计存在缺陷(我想我可以实例化一个MyDependencyFactory并在实例化MyConsumingFactory时传递它而不是使用角度的DI?)我全心全意:)

1 个答案:

答案 0 :(得分:4)

首先,您对module()的所有调用都应该在inject()之前,否则您将收到此错误:Injector already created, can not register a module!即您应该在将代码注入模块之前注册模块。知道这一点,我们需要在注入之前模拟MyDependencyFactory,但如果$q中只有inject(),我们如何获得describe('some suite', function () { // "global" variables for injected services var $rootScope, $q; beforeEach(function () { module('app'); module(function($provide) { $provide.factory('MyDependencyFactory', function () { return function () { this.doPromise = function (data) { // use "globals" var defer = $q.defer(); defer.resolve('mock data'); return defer.promise; }; }; }); }); inject(function (_$rootScope_, _$q_) { // assign to "globals" $rootScope = _$rootScope; $q = _$q; }); }); // .... }); ?实际上,它是角度测试中的常用技术,将注入的服务分配给测试套件中的全局变量,然后在所有场景中使用它:

$q

您可以在$provide块中使用$q的原因是它不会立即使用,只有在调用模拟方法或创建模拟对象的实例时才会使用它。到那时,它将被注入并分配给全局变量defer并具有适当的值。

如果要多次使用不同的值来解决您的承诺,可以做的另一个技巧是创建一个全局变量beforeEach并在特定方法内部初始化它,但在某些defer.resolve('something')块中,然后在您的方案中使用您在此特定方案中所需的值进行With Sheets("Worksheet 2") .Range("B1").Formula = "=IF(ISERROR(VLOOKUP(A1,'WorkSheet 1'!A:B,2,0))," & """""" & ",VLOOKUP(A1,'Worksheet 1'!A:B,2,0))" .Range("B1").Copy Range("B2:B" & Range("A" & Rows.Count).End(xlUp).Row) End With

Here you can see a working example of your code,我已经做了一些额外的修复工作(有评论)。

注意:我说的是“全局”变量,但它实际上并不是JS术语中的全局变量,而是特定测试套件中的全局变量。