对启用 Keycloak 的 Angular 应用程序进行单元测试
Unit Testing a Keycloak-enabled Angular app
我正在尝试为使用 Keycloak 进行身份验证的 Angular 应用编写测试套件。
但是,由于 Keycloak 需要您手动 bootstrap Angular 并设置一些拦截器,由于以下错误,我无法启动任何测试:
Error: $injector:unpr
Unknown Provider: AuthProvider <- Auth <- authInterceptor <- $http <- $templateRequest <- $route
这是引发错误的拦截器代码:
angular.module('MPMReportGenerator')
.factory('authInterceptor', function authInterceptor ($q, Auth, $log) {
return {
request: function (config) {
var deferred = $q.defer()
Auth.updateToken(5).success(function () {
config.headers = config.headers || {}
config.headers.Authorization = 'Bearer ' + Auth.token
deferred.resolve(config)
}).error(function () {
deferred.reject('Failed to refresh token')
})
$log.info(deferred.promise)
return deferred.promise
}
}
})
我的想法是我应该模拟拦截器并让它 return 请求。
但是,我看不出我该怎么做,因为这个拦截器从来没有作为依赖注入到任何地方,它只是用上面的块声明,就是这样。我对模拟服务的理解是它们需要被注入到某个地方才能被模拟。
我在 Angular 中对 Keycloak 的实现直接来自他们的例子,如果有帮助的话。
编辑
我一直在尝试将模拟的 Auth 模块注入到我正在为其编写测试的服务中,但仍然没有任何变化。
总的来说,我对单元测试还很陌生,所以我有点迷失了试图追踪这一点。我觉得我知道问题出在哪里,但不知道如何解决(在应用程序 bootstrap 期间添加了 Auth 服务,我需要模拟它才能正常工作,但似乎我没有知道 how/where 正确地模拟它)
完整的测试代码如下:
describe('Services', function () {
'use strict'
beforeEach(module('MPMReportGenerator'))
module(function ($provide) {
$provide.factory('Auth', function () {
return null
})
})
var sectionService, $httpBackend, mockAuth
beforeEach(inject(function (_sectionService_, _$httpBackend_, Auth) {
sectionService = _sectionService_
$httpBackend = _$httpBackend_
mockAuth = Auth
}))
it('should get sections', function () {
$httpBackend.expect('GET', '/MPMReportGenerator/api/categories/all').respond(200)
sectionService.getSections()
expect($httpBackend.flush).not.toThrow()
})
})
编辑 2
我已经通过制作 Auth 的模拟版本设法克服了最初的错误。
我现在面临着实现 Keycloak 的 Javascript 库的模拟版本的问题。
我目前的模拟代码如下:
beforeEach(module(function ($provide) {
$provide.factory('Auth', function ($q) {
return {
updateToken: function (minValidity) {
return {
success: function (fn) {
var deferred = $q.defer()
deferred.resolve('')
fn(deferred.promise)
},
error: function (fn) {
var deferred = $q.defer()
deferred.resolve('Error')
fn(deferred.promise)
}
}
},
token: 'thisisafaketokenfortesting'
}
})
}))
并抛出此错误:
Expected function not to throw, but it threw TypeError: undefined is not an object (near '...}).error(function () {...').
target/MPMReportGenerator-1.0.0/js/app.service.spec.js:42:43
loaded@http://localhost:9876/context.js:151:17
我的实际测试是这样的:
it('should get sections', function () {
$httpBackend.expect('GET', '/MPMReportGenerator/api/categories/all').respond(200)
sectionService.getSections()
expect($httpBackend.flush).not.toThrow()
})
终于想通了
如果有人想用 keycloak 测试 Angular 应用程序,这里是所需的代码:
beforeEach(
module(function ($provide) {
$provide.factory('Auth', function ($q) {
return {
updateToken: function (minValidity) {
return {
success: function () {
return {
error: function () {
var deferred = $q.defer()
return deferred.promise
}
}
}
}
},
token: 'thisisafaketokenfortesting'
}
})
}))
请注意,如果您打算测试官方示例中提供的拦截器,您可能需要模拟 keycloak 库的其他部分。
编辑
不要使用上面的代码,下面的代码效果更好:
$provide.factory('Auth', function () {
return {
updateToken: function (minValidity) {
return {
success: function () {
return this
},
error: function () {
return this
}
}
},
token: 'thisisafaketokenfortesting'
}
})
我正在尝试为使用 Keycloak 进行身份验证的 Angular 应用编写测试套件。
但是,由于 Keycloak 需要您手动 bootstrap Angular 并设置一些拦截器,由于以下错误,我无法启动任何测试:
Error: $injector:unpr
Unknown Provider: AuthProvider <- Auth <- authInterceptor <- $http <- $templateRequest <- $route
这是引发错误的拦截器代码:
angular.module('MPMReportGenerator')
.factory('authInterceptor', function authInterceptor ($q, Auth, $log) {
return {
request: function (config) {
var deferred = $q.defer()
Auth.updateToken(5).success(function () {
config.headers = config.headers || {}
config.headers.Authorization = 'Bearer ' + Auth.token
deferred.resolve(config)
}).error(function () {
deferred.reject('Failed to refresh token')
})
$log.info(deferred.promise)
return deferred.promise
}
}
})
我的想法是我应该模拟拦截器并让它 return 请求。 但是,我看不出我该怎么做,因为这个拦截器从来没有作为依赖注入到任何地方,它只是用上面的块声明,就是这样。我对模拟服务的理解是它们需要被注入到某个地方才能被模拟。
我在 Angular 中对 Keycloak 的实现直接来自他们的例子,如果有帮助的话。
编辑
我一直在尝试将模拟的 Auth 模块注入到我正在为其编写测试的服务中,但仍然没有任何变化。
总的来说,我对单元测试还很陌生,所以我有点迷失了试图追踪这一点。我觉得我知道问题出在哪里,但不知道如何解决(在应用程序 bootstrap 期间添加了 Auth 服务,我需要模拟它才能正常工作,但似乎我没有知道 how/where 正确地模拟它)
完整的测试代码如下:
describe('Services', function () {
'use strict'
beforeEach(module('MPMReportGenerator'))
module(function ($provide) {
$provide.factory('Auth', function () {
return null
})
})
var sectionService, $httpBackend, mockAuth
beforeEach(inject(function (_sectionService_, _$httpBackend_, Auth) {
sectionService = _sectionService_
$httpBackend = _$httpBackend_
mockAuth = Auth
}))
it('should get sections', function () {
$httpBackend.expect('GET', '/MPMReportGenerator/api/categories/all').respond(200)
sectionService.getSections()
expect($httpBackend.flush).not.toThrow()
})
})
编辑 2
我已经通过制作 Auth 的模拟版本设法克服了最初的错误。
我现在面临着实现 Keycloak 的 Javascript 库的模拟版本的问题。
我目前的模拟代码如下:
beforeEach(module(function ($provide) {
$provide.factory('Auth', function ($q) {
return {
updateToken: function (minValidity) {
return {
success: function (fn) {
var deferred = $q.defer()
deferred.resolve('')
fn(deferred.promise)
},
error: function (fn) {
var deferred = $q.defer()
deferred.resolve('Error')
fn(deferred.promise)
}
}
},
token: 'thisisafaketokenfortesting'
}
})
}))
并抛出此错误:
Expected function not to throw, but it threw TypeError: undefined is not an object (near '...}).error(function () {...').
target/MPMReportGenerator-1.0.0/js/app.service.spec.js:42:43
loaded@http://localhost:9876/context.js:151:17
我的实际测试是这样的:
it('should get sections', function () {
$httpBackend.expect('GET', '/MPMReportGenerator/api/categories/all').respond(200)
sectionService.getSections()
expect($httpBackend.flush).not.toThrow()
})
终于想通了
如果有人想用 keycloak 测试 Angular 应用程序,这里是所需的代码:
beforeEach(
module(function ($provide) {
$provide.factory('Auth', function ($q) {
return {
updateToken: function (minValidity) {
return {
success: function () {
return {
error: function () {
var deferred = $q.defer()
return deferred.promise
}
}
}
}
},
token: 'thisisafaketokenfortesting'
}
})
}))
请注意,如果您打算测试官方示例中提供的拦截器,您可能需要模拟 keycloak 库的其他部分。
编辑
不要使用上面的代码,下面的代码效果更好:
$provide.factory('Auth', function () {
return {
updateToken: function (minValidity) {
return {
success: function () {
return this
},
error: function () {
return this
}
}
},
token: 'thisisafaketokenfortesting'
}
})