Angularjs 用Jasmine测试角度异步服务

Angularjs 用Jasmine测试角度异步服务,angularjs,jasmine,integration-testing,Angularjs,Jasmine,Integration Testing,我试图用Jasmine(集成测试)测试一个真正的http调用,但是当我调用一个使用$http.get的方法时,它会超时,服务器永远不会被调用 我知道我应该注入$http的实现,但不确定应该在哪里注入 searchSvc app.service('searchSvc', ['$http', '$q', searchSvc]); function searchSvc($http, $q) { return { search: function(text) { console.

我试图用Jasmine(集成测试)测试一个真正的http调用,但是当我调用一个使用$http.get的方法时,它会超时,服务器永远不会被调用

我知道我应该注入$http的实现,但不确定应该在哪里注入

searchSvc

app.service('searchSvc', ['$http', '$q', searchSvc]);
function searchSvc($http, $q) {
  return {
    search: function(text) {
      console.log('svc.search called with ', text); // this does get called 
      return $q.when($http.get('/search/' + text));
    }
  };
}
describe("searchTest", function() {
  var ctrl, svc, $http;

  beforeEach(function () {
      module('testApp');
    inject(function(_$controller_, searchSvc, _$http_){
      ctrl = _$controller_('searchCtrl');
      svc = searchSvc;
      $http = _$http_;
    })
  });

  it('test server search', function(done) {
      svc.search('re').then(function(result) {
        console.log('promise then'); // this never gets called, because server never gets called
        expect(result).not.toBeNull();
        expect(result.data).not.toBeNull();
        expect(result.data.length).toBeGreaterThan(0);

        done();
      });
  });
searchSpec

app.service('searchSvc', ['$http', '$q', searchSvc]);
function searchSvc($http, $q) {
  return {
    search: function(text) {
      console.log('svc.search called with ', text); // this does get called 
      return $q.when($http.get('/search/' + text));
    }
  };
}
describe("searchTest", function() {
  var ctrl, svc, $http;

  beforeEach(function () {
      module('testApp');
    inject(function(_$controller_, searchSvc, _$http_){
      ctrl = _$controller_('searchCtrl');
      svc = searchSvc;
      $http = _$http_;
    })
  });

  it('test server search', function(done) {
      svc.search('re').then(function(result) {
        console.log('promise then'); // this never gets called, because server never gets called
        expect(result).not.toBeNull();
        expect(result.data).not.toBeNull();
        expect(result.data.length).toBeGreaterThan(0);

        done();
      });
  });

如果您使用承诺,您可以在这里找到如何处理承诺,这是一种假设,但如果您同时包括
ngMock
&
ngMockE2E
模块作为应用程序模块的依赖项(
ngMock
需要在依赖项列表中位于
ngMockE2E
之前)您应该能够使用
ngMockE2E
模块提供的
$httpBackend
服务来
passThrough
对测试规范中实际后端的搜索api调用

尝试类似的方法,看看是否有效:

describe("searchTest", function() {
  var ctrl, svc, $httpBackend;

  beforeEach(function () {
    module('testApp');
    inject(function(_$controller_, searchSvc, _$httpBackend_){
      $httpBackend = _$httpBackend_;
      ctrl = _$controller_('searchCtrl');
      svc = searchSvc;
    });
  });

  it('test server search', function(done) {
      $httpBackend.whenGET(/^\/search\//).passThrough();
      svc.search('re').then(function(result) {
        console.log('promise then'); // this never gets called, because server never gets called
        expect(result).not.toBeNull();
        expect(result.data).not.toBeNull();
        expect(result.data.length).toBeGreaterThan(0);

        done();
      });
  });
});

当我使用ngMock进行单元测试时,我使用这个解决方案来进行真正的HTTP调用。我主要使用它进行调试、完成测试、获取JSON示例等

我在我的博客上写了一篇关于解决方案的更详细的帖子:

解决办法如下:

angular.mock.http = {};

angular.mock.http.init = function() {

  angular.module('ngMock', ['ng', 'ngMockE2E']).provider({
    $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
    $log: angular.mock.$LogProvider,
    $interval: angular.mock.$IntervalProvider,
    $rootElement: angular.mock.$RootElementProvider
  }).config(['$provide', function($provide) {
    $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
    $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
    $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
    $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
    $provide.decorator('$controller', angular.mock.$ControllerDecorator);
  }]);

};

angular.mock.http.reset = function() {

  angular.module('ngMock', ['ng']).provider({
    $browser: angular.mock.$BrowserProvider,
    $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
    $log: angular.mock.$LogProvider,
    $interval: angular.mock.$IntervalProvider,
    $httpBackend: angular.mock.$HttpBackendProvider,
    $rootElement: angular.mock.$RootElementProvider
  }).config(['$provide', function($provide) {
    $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
    $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
    $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
    $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
    $provide.decorator('$controller', angular.mock.$ControllerDecorator);
  }]);

};
在ngMock之后包含此源文件,例如:

<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="angular-mocks.js"></script>
<!-- this would be the source code just provided -->
<script type="text/javascript" src="ngMockHttp.js"></script>
它是如何工作的? 它使用ngMockE2E版本的$httpBackEndProvider,它为我们提供了测试中使用的传递函数。这是顾名思义的,允许本地HTTP调用通过


我们需要在不使用$BrowserProvider的伪版本的情况下重新定义ngMock模块,因为这是在使用ngMock的单元测试中阻止真正HTTP调用的原因。

我不确定它是否允许您这样做。。。这不是真正的单元测试。这是一个集成测试。我相信这样做的目的是使用
$httpBackend
mock测试调用服务器的代码,并使用自己的单元测试测试服务器本身,最后编写端到端测试,以确保它们都能正常工作。这些将使用量角器运行,并在没有模拟的情况下测试实际应用程序。对,我从来没有说过这是一个单元测试。我正在尝试使用Jasmine进行集成测试和单元测试。我懂了。现在我也很好奇。我删除了angular Mock,从一个实际的angular模块中引用了$http并尝试了这一点,但它也从来没有解决这个问题。我认为在一个正常运行的应用程序中,有一些应该在内部发生的事情在这里是不会发生的。有点像我们在测试中必须手动调用
$scope.$digest
。我猜这与依赖注入的工作方式有关吧?我见过一些控制器的例子,其中可以在Jasmine块中提供依赖项的实现,但找不到servicesCheck的符号:嗯,我不确定这是否是承诺问题,因为searchSvc.search被触发。问题是服务器从来没有被调用过。感谢您发布此消息!我仍然感到震惊的是,在茉莉花中进行端到端测试是如此的困难。。我一定会尝试你的方法并向你汇报。再次感谢