我有一个标准的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
现在我试图用Karma& amp; Jasmine测试responseError函数是否正常工作。我已经检查了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
答案 0 :(得分: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);
}))
});