[英]Unit testing Angular HTTP interceptor
I have a standard HTTP interceptor as a factory: 我有一个标准的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');
}
}
}
In manual testing, I can see this works correctly by redirecting the user to the relevant 404 or error page if an HTTP call returns an error response. 在手动测试中,如果HTTP调用返回错误响应,则可以通过将用户重定向到相关的404或错误页面来看到此方法是否正确。 The basic principal of this is documented by Angular here: https://docs.angularjs.org/api/ng/service/ $http#interceptors Angular在此处记录了其基本原理: https : //docs.angularjs.org/api/ng/service/ $ http#interceptors
Now I'm trying to write a unit test with Karma & Jasmine to test that the responseError function works correctly. 现在,我正在尝试使用Karma&Jasmine编写单元测试,以测试responseError函数是否正常工作。 I've checked out this SO answer to help me. 我已经检查了这个SO答案来帮助我。 My test looks like this: 我的测试看起来像这样:
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');
});
});
});
My test passes the Exists with required methods
check but fails Sets window location
with the following error: 我的测试通过了Exists with required methods
的Exists with required methods
检查,但未通过以下错误Sets window location
:
Error: [$injector:unpr] Unknown provider: $stateProvider <- $state
The module doesn't seem to have ui.router
module loaded, hence $state
service is undefined. 该模块似乎未加载ui.router
模块,因此$state
服务未定义。 This is fine, because real router introduces extra moving parts and is highly undesirable in unit tests. 很好,因为真正的路由器会引入额外的运动部件,并且在单元测试中是非常不希望的。
For functional test it is normal to treat a unit as a blackbox, provide initial conditions and test the results, asserting window.location
would be appropriate. 对于功能测试,通常将一个单元视为黑盒,提供初始条件并测试结果,断言window.location
是合适的。
For unit test there's no need to treat a unit as a blackbox, $state
service may be stubbed: 对于单元测试,无需将单元视为黑盒, $state
服务可能会存根:
var statePromiseMock = {};
beforeEach(module('app.services', {
$state: {
go: jasmine.createSpy().and.returnValue(statePromiseMock)
}
}));
And tested like: 并测试如下:
it('...', inject(function (HttpInterceptorService, $state) {
var state404Promise = HttpInterceptorService.responseError({ status: 404 });
expect($state.go).toHaveBeenCalledWith('404');
expect(state404Promise).toBe(statePromiseMock);
...
}))
Ie it may be something like 即可能是这样的
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);
}))
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.