圣杯。测试带有 spring bean 的命令对象
Grails. Testing command objects with spring beans inside
我有一个带有约束的命令对象,在自定义验证器中使用 spring bean:
class UserPasswordCommand {
String currentPassword
//other fields....
static constraints = {
currentPassword validator: { currPass, upc ->
Holders.applicationContext.passwordEncoder.isPasswordValid(
Holders.applicationContext.springSecurityService.currentUser.password, currPass, null)
}
}
}
但是在单元测试中调用 new UserPasswordCommand(...) 时,我得到以下信息:
java.lang.NullPointerException: Cannot get property 'currentUser' on
null object
所以看起来 springSecurityService = null(正如预期的那样)。我尝试了不同的操作来模拟或 "metaClass" 但没有成功。
请告知是否有更好的方法在命令对象中使用 applicationContext 中的 bean 或在 Holders.applicationContext 中使用一些模拟 bean 的方法。
提前致谢!
更新
将以下内容放入 setup()
部分:
def setup() {
def appContext = Mock(ApplicationContext)
def springSecurityService = Mock(SpringSecurityService)
appContext.springSecurityService >> springSecurityService
Holders.metaClass.static.applicationContext = { appContext }
}
但是没有效果。 spring从 Holders 检索到的 applicationContext 中的 null。我做错了什么?
您可以像这样覆盖 Holder.applicationContext:
def setup() {
ApplicationContext appContext = Mock()
PasswordEncoder passwordEncoder = Mock()
passwordEncoder.isPasswordValid(_, _, _) >> true
appContext.passwordEncoder >> passwordEncoder //you can do the same for springSecurityService
//override Holder.getAplicationContext() method to return mocked context
Holders.metaClass.static.applicationContext = { appContext }
}
我通过删除原始命令对象中的 Holders
解决了这个问题:
class UserPasswordCommand {
static passwordEncoder
static springSecurityService
String currentPassword
//...
static constraints = {
currentPassword validator: { currPass, upc ->
passwordEncoder.isPasswordValid(springSecurityService.currentUser.password, currPass, null)
}
//...
}
}
将 mocks/stubs 添加到测试测试:
def springSecurityService = Mock(SpringSecurityService)
def passwordEncoder = Mock(PasswordEncoder)
def setup() {
passwordEncoder.isPasswordValid(_, _, _) >> Boolean.TRUE
springSecurityService.currentUser >> Mock(User)
}
和:
given:
Map props = [
currentPassword: CURRENT_PASSWORD,
passwordEncoder: passwordEncoder,
springSecurityService: springSecurityService,
]
expect:
new UserPasswordCommand(props).validate()
我有一个带有约束的命令对象,在自定义验证器中使用 spring bean:
class UserPasswordCommand {
String currentPassword
//other fields....
static constraints = {
currentPassword validator: { currPass, upc ->
Holders.applicationContext.passwordEncoder.isPasswordValid(
Holders.applicationContext.springSecurityService.currentUser.password, currPass, null)
}
}
}
但是在单元测试中调用 new UserPasswordCommand(...) 时,我得到以下信息:
java.lang.NullPointerException: Cannot get property 'currentUser' on null object
所以看起来 springSecurityService = null(正如预期的那样)。我尝试了不同的操作来模拟或 "metaClass" 但没有成功。
请告知是否有更好的方法在命令对象中使用 applicationContext 中的 bean 或在 Holders.applicationContext 中使用一些模拟 bean 的方法。
提前致谢!
更新
将以下内容放入 setup()
部分:
def setup() {
def appContext = Mock(ApplicationContext)
def springSecurityService = Mock(SpringSecurityService)
appContext.springSecurityService >> springSecurityService
Holders.metaClass.static.applicationContext = { appContext }
}
但是没有效果。 spring从 Holders 检索到的 applicationContext 中的 null。我做错了什么?
您可以像这样覆盖 Holder.applicationContext:
def setup() {
ApplicationContext appContext = Mock()
PasswordEncoder passwordEncoder = Mock()
passwordEncoder.isPasswordValid(_, _, _) >> true
appContext.passwordEncoder >> passwordEncoder //you can do the same for springSecurityService
//override Holder.getAplicationContext() method to return mocked context
Holders.metaClass.static.applicationContext = { appContext }
}
我通过删除原始命令对象中的 Holders
解决了这个问题:
class UserPasswordCommand {
static passwordEncoder
static springSecurityService
String currentPassword
//...
static constraints = {
currentPassword validator: { currPass, upc ->
passwordEncoder.isPasswordValid(springSecurityService.currentUser.password, currPass, null)
}
//...
}
}
将 mocks/stubs 添加到测试测试:
def springSecurityService = Mock(SpringSecurityService)
def passwordEncoder = Mock(PasswordEncoder)
def setup() {
passwordEncoder.isPasswordValid(_, _, _) >> Boolean.TRUE
springSecurityService.currentUser >> Mock(User)
}
和:
given:
Map props = [
currentPassword: CURRENT_PASSWORD,
passwordEncoder: passwordEncoder,
springSecurityService: springSecurityService,
]
expect:
new UserPasswordCommand(props).validate()