首页 文章

单元测试Angular HTTP拦截器

提问于
浏览
0

我有一个标准的HTTP拦截器作为工厂:

angular
  .module('app.services')
  .factory('HttpInterceptorService', HttpInterceptorService);

function HttpInterceptorService($injector) {

  // Callable functions
  var service = {
    response: response,
    responseError: responseError
  };

  return service;

  // Pass through clean response
  function response(data) {
    return data;
  }

  // Handle error response
  function responseError(rejection) {

    // Handle bypass requests
    if (angular.isDefined(rejection.config) && rejection.config.bypassInterceptor) {
      return rejection;
    }

    // Get $state via $injector to avoid a circular dependency
    var state = $injector.get('$state');

    switch (rejection.status) {
      case 404:
        return state.go('404');
        break;
      default:
        return state.go('error');
    }
  }

}

在手动测试中,如果HTTP调用返回错误响应,我可以通过将用户重定向到相关的404或错误页面来正常工作 . 这里的基本原理由Angular记录:https://docs.angularjs.org/api/ng/service/ $ http #interceptors

现在我'm trying to write a unit test with Karma & Jasmine to test that the responseError function works correctly. I'已经检查了this SO answer来帮助我 . 我的测试看起来像这样:

describe('HttpInterceptorService', function() {

  // Bindable members
  var $window,
      HttpInterceptorService;

  // Load module
  beforeEach(module('app.services'));

  // Set window value
  beforeEach(function () {
    $window = { location: { href: null } };

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

  // Bind references to global variables
  beforeEach(inject(function(_HttpInterceptorService_) {
    HttpInterceptorService = _HttpInterceptorService_;
  }));

  // Check service exists with methods
  it('Exists with required methods', function() {
    expect(HttpInterceptorService).toBeDefined();
    expect(angular.isFunction(HttpInterceptorService.response)).toBe(true);
    expect(angular.isFunction(HttpInterceptorService.responseError)).toBe(true);
  });

  // Test 404 HTTP response
  describe('When HTTP response 404', function () {
    beforeEach(function() {
      HttpInterceptorService.responseError({ status: 404 });
    });

    it('Sets window location', function () {
      expect($window.location.href).toBe('/404');
    });
  });

});

我的测试通过 Exists with required methods 检查但是 Sets window location 失败并出现以下错误:

Error: [$injector:unpr] Unknown provider: $stateProvider <- $state

1 回答

  • 1

    该模块似乎没有加载 ui.router 模块,因此 $state 服务未定义 . 这很好,因为真正的路由器引入了额外的移动部件,在单元测试中是非常不受欢迎的 .

    对于功能测试,将单元视为黑盒,提供初始条件并测试结果是正常的,断言 window.location 是合适的 .

    对于单元测试,不需要将单元视为黑盒子, $state 服务可能是存根的:

    var statePromiseMock = {};
    beforeEach(module('app.services', {
      $state: {
        go: jasmine.createSpy().and.returnValue(statePromiseMock)
      }
    }));
    

    并测试如下:

    it('...', inject(function (HttpInterceptorService, $state) {
        var state404Promise = HttpInterceptorService.responseError({ status: 404 });
        expect($state.go).toHaveBeenCalledWith('404');
        expect(state404Promise).toBe(statePromiseMock);
        ...
    }))
    

    即它可能是这样的

    describe('HttpInterceptorService', function() {
    
      // Bindable members
      var HttpInterceptorService;
    
      var statePromiseMock = {};
      beforeEach(module('app.services', {
        $state: {
          go: jasmine.createSpy().and.returnValue(statePromiseMock)
        }
      }));
    
      // Bind references to global variables
      beforeEach(inject(function(_HttpInterceptorService_) {
        HttpInterceptorService = _HttpInterceptorService_;
      }));
    
      // Check service exists with methods
      it('Exists with required methods', function() {
        expect(HttpInterceptorService).toBeDefined();
        expect(angular.isFunction(HttpInterceptorService.response)).toBe(true);
        expect(angular.isFunction(HttpInterceptorService.responseError)).toBe(true);
      });
    
      it('...', inject(function($state) {
        var state404Promise = HttpInterceptorService.responseError({
          status: 404
        });
        expect($state.go).toHaveBeenCalledWith('404');
        expect(state404Promise).toBe(statePromiseMock);
      }))
    
    });
    

相关问题