$ httpBackend decorator

时间:2016-06-07 12:06:13

标签: angularjs unit-testing jasmine httpbackend

所以我有一种情况,我们不得不打一个平静的"不受我们控制的服务,为了在GET调用中从服务中恢复json,我们必须传递Content-Type =" application / json"在标题中。唯一的问题是Angular从GET上的请求标头中剥离Content-Type。我发现了一篇博文,建议在$ httpBackend上使用装饰器,它允许我们在发送之前截取调用并添加回内容类型:

angular
.module('MyApp')
.decorator('$httpBackend', [
  '$delegate', function($delegate) {
      return function() {
          var contentType, headers;
          headers = arguments[4];
          contentType = headers != null ? headers['X-Force-Content-Type'] : null;
          if (contentType != null && headers['Content-Type'] == null)
            headers['Content-Type'] = contentType;

          return $delegate.apply(null, arguments);
      };
  }]);

所以,这很好用!现在我们的问题是它已经破坏了我们使用模拟$ httpBackend服务的所有单元测试。我们得到的唯一错误是"未定义"。

实施例。单元测试方法:

it('should return service.model.error if service returns an exception code from EndProject', 
 inject(function($httpBackend) {
      var mockResponse = sinon.stub({ 'exception': 'Unable to retrieve service data' });
      $httpBackend.whenPUT(this.endProjectUrl).respond(mockResponse);
      var data;
      this.service.EndProject().then(function(fetchedData) {
           data = fetchedData;
      });

      $httpBackend.flush();
      expect(data.error.state).toBe(true);
      expect(data.error.message).toEqual('Unable to retrieve service data');
 }));
  

PhantomJS 2.1.1(Mac OS X 0.0.0)如果服务从EndProject FAILED返回异常代码,则ProjectService EndProject应该返回service.model.error       未定义       /Users/mlm1205/Documents/THDSource/bolt-projects/html_app/src/app/components/services/project/projectService.spec.js:213:41       invoke@/Users/mlm1205/Documents/THDSource/bolt-projects/html_app/bower_components/angular/angular.js:4560:22       workFn@/Users/mlm1205/Documents/THDSource/bolt-projects/html_app/bower_components/angular-mocks/angular-mocks.js:2518:26

2 个答案:

答案 0 :(得分:1)

列出的装饰器包含简单的猴子修补方案,其中修补的函数不是构造函数,并且没有静态属性和方法。

这对于$httpBackend in ng module来说是正确的,它只是一个没有额外属性的工厂函数。

对于覆盖ngMock且具有静态方法at least some of them are documentedngMockE2E$httpBackend模块,情况并非如此。

这意味着通常安全的配方(它不包括非可枚举和继承的属性)用于猴子修补工厂功能

app.decorator('$httpBackend', ['$delegate', function ($delegate) {
    var $httpBackend = function () {
        ...
        return $delegate.apply(null, arguments);
    };
    angular.extend($httpBackend, $delegate);
    return $httpBackend;
}]);

无论如何,将应用程序模块化到可以单独测试单元而没有过多移动部件的水平是一个好习惯(这个问题是一个表达为什么这很重要的例子)。让app(在生产中引导),app.e2e(在e2e测试中引导),app.common(公分母),app.unitA(在{{1}中加载)很方便并且可以在单元测试中单独加载)等。

大多数应用程序范围的代码(app.commonconfig块,路由)可以移动到单独的模块中,并仅加载到直接依赖于它们的模块中。除非这是一个测试run单元本身的规范,否则不应加载装饰模块。

在调试规范错误时,请注意Chrome may offer superior experience比PhantomJS。

答案 1 :(得分:0)

虽然我将estus的答案标记为解决方案,但纯粹基于我的问题......最终,最终并不是我们最终的结果。在没有通过树看到森林的情况下,最简单的解决方案是在$ http调用的配置中添加一个空数据元素。我之前尝试过它并且它不起作用(或者看起来似乎如此),但在再次使用它之后,它确实起作用了,我们能够从应用程序中删除装饰器。

return $http.get(getItemInformationUrl + params, { dataType: 'json', data: '', headers: {'Content-Type': 'application/json'} }).then(getItemInformationCompleted).catch(getItemInformationFailed);