2015-04-28 82 views
4

我想测试一个Angular服务,它有两个依赖关系,一个在$ q上,另一个在'myService'上,它也依赖于$ q。

(function() { 
    'use strict'; 

    angular.module('myModule').factory('myService', [ 
     '$q', 
     'apiService', 
     function($q, apiService) { 

      var data = null; 

      function getData() { 
       var deferred = $q.defer(); 

       if (data === null) { 

        apiService.get('url').then(function(result) { 
         data = result; 
         deferred.resolve(data); 
        }, function() { 
         deferred.reject(); 
        }); 
       } else { 
        deferred.resolve(data); 
       } 

       return deferred.promise; 
      } 

      return { 
       getData: getData 
      }; 
     } 
    ]); 
})(); 

我开始写一个茉莉花测试,如下所示,但有问题嘲笑$ q。我想注入$ q的真实版本而不是模拟版本到'myService'和'apiService',但我不确定如何完成。

'use strict'; 

describe('My service', function() { 
    var qSpy, apiServiceSpy; 

    beforeEach(module('myModule')); 

    beforeEach(function() { 
     qSpy = jasmine.createSpyObj('qSpy', ['defer']); 

     apiServiceSpy = jasmine.createSpyObj('apiServiceSpy', ['get']); 
     apiServiceSpy.get.and.callFake(function() { 
      var deferred = $q.defer(); 
      deferred.resolve('Remote call result'); 
      return deferred.promise; 
     }); 

     module(function($provide) { 
      $provide.value('$q', qSpy); 
      $provide.value('apiService', apiServiceSpy); 
     }); 
    }); 

    it('should get data.', inject(function(myService) { 
     // Arrange 

     // Act 
     var data = myService.getData(); 

     // Assert 
     expect(data).not.toBeNull(); 
    })); 
}); 

编辑 这是基于下面的反应更新的测试。我想我的问题是我认为我必须提供$ q。

'use strict'; 

describe('My service', function() { 
    var service, apiServiceSpy; 

    beforeEach(module('myModule')); 

    beforeEach(function() { 
     apiServiceSpy = jasmine.createSpyObj('apiServiceSpy', ['get']); 

     module(function($provide) { 
      $provide.value('apiService', apiServiceSpy); 
     }); 
    }); 

    beforeEach(inject(function($q, myService) { 
     service = myService; 

     apiServiceSpy.get.and.callFake(function() { 
      var deferred = $q.defer(); 
      deferred.resolve('Remote call result'); 
      return deferred.promise; 
     }); 
    })); 

    it('should get data.', function() { 
     // Arrange 

     // Act 
     var data = service.getData(); 

     // Assert 
     expect(data).not.toBeNull(); 
    })); 
}); 
+0

你为什么要模拟'$ q'呢?有什么问题只是使用真正的'$ q' – hansmaad

回答

9

您可以使用真正的$ Q。需要注意的是,您应该致电$scope.$apply()解决承诺。

var service; 
var $scope; 
beforeEach(function() { 

    angular.mock.module('app', function ($provide) { 
     $provide.value('apiService', apiServiceSpy); 
    }); 

    angular.mock.inject(function (_myService_, _$rootScope_) { 
     service = _myService_; 
     $scope = _$rootScope_; 
    }); 
}); 

it('works like a charm', function() { 
    var data; 
    service.getData().then(function(d) { 
     data = d; 
    }); 
    $scope.$apply(); // resolve promise 
    expect(data).toBeAwesomeData(); 
}); 
+0

谢谢!我想我的问题是我认为我必须提供$ q。 – Jason

+0

另一个重要的注意事项:如果你的承诺包含一个$ http请求,你需要在'$ scope。$ apply()'之前执行'$ httpBackend.flush()',否则承诺将无法正确解析。如果你将两者结合起来,这在大多数情况下是不必要的(因为$ http被promisified开始),但是我遇到了需要这种方法的组合实例。 – cm92

0

您应该在真正的$q服务中使用。

var rootScope; 
var deferrred; 
var fakeMyService = { getData: function() { return deferred.promise}}; 

beforEach(inject(function($q, $rootScope) { 
    deferred = $q.defer(); 
    rootScope = $rootScope; 
})) 

it('should do something', function() { 
    . . .   

    deferred.resove(<something>); 
    $rootScope.$digest(); 

    . . . 
    expect(. . .) 

}) 
2

您必须使用$injector服务才能获得真正的角度服务。

$注入器用于检索提供程序定义的对象实例, 实例化类型,调用方法和加载模块。

var $q 
beforeEach(inject(function($injector) { 
    $q = $injector.get('$q'); 
})); 
相关问题