在AngularJS单元/集成测试中向HTTP服务器发出实际请求 [英] Making real requests to HTTP server in AngularJS unit/integration tests

查看:168
本文介绍了在AngularJS单元/集成测试中向HTTP服务器发出实际请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Angular 1.x单元/集成测试中发出未使用 $ httpBackend.when 进行模拟的请求会导致错误:

Making a request that wasn't mocked with $httpBackend.when in Angular 1.x unit/integration test results in an error:


错误:意外请求:GET / real-request

Error: Unexpected request: GET /real-request

是吗可以使用 ngMock 和Karma + Jasmine测试平台进行真正的HTTP请求?这样做的好习惯是什么?

Is it possible to make real HTTP requests with ngMock and Karma+Jasmine test rig? What is a good practice to do that?

推荐答案

AngularJS是一个自以为是的框架,它对单元测试中HTTP请求的看法是所有这些都应该被模拟。

AngularJS is opinionated framework, and its opinion on HTTP requests in unit tests is that all of them should be mocked.

由于两个原因,不建议在单元测试中进行真正的HTTP请求。单元测试应该是隔离的并且速度很快。发出实际请求会使测试异步,从而显着降低测试运行速度。提出真正的请求会打破隔离,如果测试通过,则取决于测试单元和后端。

It is not advisable to do real HTTP requests in unit tests for two reasons. Unit tests are supposed to be isolated and be fast. Making a real request makes a test asynchronous, which slows down test runs significantly. Making a real request breaks the isolation, the fact if a test passes depends on both tested unit and a backend.

AngularJS ngMock 模块(它由angular-mocks.js在单元测试中自动加载)。开发人员几乎不会使用Angular 异步 Jasmine单元测试,因为没有必要这样做。

This was taken into consideration when AngularJS ngMock module was designed (it is loaded automatically in unit tests by angular-mocks.js). The developer will hardly ever do asynchronous Jasmine unit tests with Angular, because there's no need to do that.

集成测试有所不同。它们可能不像E2E测试那样广泛(通常由Protractor运行)并测试多个单元如何协同工作,这可能包括后端(HTTP服务器)。所以最终仍然使用了Karma和Jasmine,但是测试可能更慢并且异步并且执行真正的HTTP请求。

Integration tests differ. They may be not as broad as E2E tests (which are often run by Protractor) and test how several units work together, this may include a backend (HTTP server). So in the end Karma and Jasmine are still used, but the tests may be slower and asynchronous and do real HTTP requests.

这是 ngMockE2E 模块(通常在E2E测试中使用)启动。它与angular-mocks.js一起包含在 ngMock 中,但默认情况下不加载。

This is where ngMockE2E module (usually used in E2E tests) kicks in. It is included in angular-mocks.js alongside with ngMock but isn't loaded by default.


ngMockE2E是一个AngularJS模块,它包含适用于端到端测试的模拟。目前该模块中只有一个模拟 - e2e $ httpBackend mock。

The ngMockE2E is an AngularJS module which contains mocks suitable for end-to-end testing. Currently there is only one mock present in this module - the e2e $httpBackend mock.

ngMockE2E 包含可用于此目的的不同 $ httpBackend 实现。它的API各不相同。它不应该使用 flush extend 方法。 $ rootScope。$ digest()如果有 $ q 应该执行的承诺链,则可以使用。

ngMockE2E contains different $httpBackend implementation which can be used for the purpose. Its API varies. It isn't supposed to use flush and extend methods. $rootScope.$digest() may be used if there are $q promise chains that should be executed.

ngMockE2E 无法正常使用,因为 ngMock 当使用其辅助函数 module inject 时。可以使用用于集成测试的辅助模块:

ngMockE2E won't work out of the box properly because of the the adjustments that are being made to Angular services by ngMock when its helper functions module and inject are used. A helper module for intergration tests can be used instead:

angular.module('ngMockI9n', []).config(function ($provide) {
  // hack to restore original implementations which were overridden by ngMock
  angular.injector(['ng', function ($httpBackendProvider, $browserProvider) {
    $provide.provider('$httpBackend', $httpBackendProvider);
    $provide.provider('$browserI9n', $browserProvider);
  }]);

  // make ngMockE2E $httpBackend use original $browser
  var httpBackendI9nDecorator = angular.mock.e2e.$httpBackendDecorator
  .map(function (dep) {
    return (dep === '$browser') ? '$browserI9n' : dep;
  });
  $provide.decorator('$httpBackend', httpBackendI9nDecorator);
});

此外,列入白名单的真实HTTP请求可以使测试更容易,尽管最佳做法是明确枚举真实和模拟请求。

Additionally, a recipe for whitelisted real HTTP requests can be used to make the testing easier, although the best practice is to enumerate real and mocked requests explicitly.

beforeEach(module('app'));  
beforeEach(module('ngMockI9n'));

beforeEach(inject(function ($httpBackend) {
  $httpBackend.when('GET', '/mocked-request').respond(200, {});

  // all other requests will be automatically whitelisted and treated as real
  // so make sure that mocked requests are mocked above this point
  angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD', 'PUT', 'POST', 'PATCH'],
  function (method) {
    $httpBackend.when(method).passThrough();
  });
}));


it('does real async request', function (done) {
  // async tests need extra `done` param
  inject(function () {
    $http.get('real-request').then(function (response) {
      expect(response.data).toEqual(...);
    })
    .then(done, done.fail);

    $rootScope.$digest();
  });
});

it('does mocked sync request', function (done) {
  // tests with mocked requests are async, too
  inject(function () {
    $http.get('mocked-request').then(function (response) {
      expect(response.data).toEqual(...);
    })
    .then(done, done.fail);

    $rootScope.$digest();
  });
});

TL; DR:使用 $ httpBackend 来自 ngMockE2E 在实际请求的集成测试中,这需要一些额外的工作才能使其与 ngMock 兼容。在单元测试中永远不要做真正的请求,这会导致测试缓慢且无用。

TL;DR: Use $httpBackend from ngMockE2E in integration tests for real requests, this requires some extra work to make it compatible with ngMock. Never do real requests in unit tests, this results in slow and trashy tests.

这篇关于在AngularJS单元/集成测试中向HTTP服务器发出实际请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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