Grails 使用 Spring Security Core 插件测试用户角色自定义验证约束
我确信这是一个相当普遍的情况。我正在使用 Spring Security Core 插件,并且想要创建一个域模型,该域模型的 Person 仅限于某些角色:
class Workgroup {
Person manager
...
static constraints = {
manager(validator: {mgr ->
// it feels like there should be a more elegant, groovy way of doing this.
def auths = mgr.getAuthorities();
def returny = false
auths.each {
if(it.authority == 'ROLE_MANAGER')
{
returny = true
}
}
return returny
})
}
}
此测试像 mofo 一样失败:
void testInvalidManager() {
def nick = new Person(username:'Nick')
def nonManagerRole = new Role(authority:'ROLE_EMPLOYEE')
UserRole.create(nick,nonManagerRole)
def awesome = new Workgroup(name:'mooCows', manager:nick)
mockForConstraintsTests(Workgroup, [awesome])
assertFalse awesome.validate()
assertEquals "validator", awesome.errors["manager"]
}
testInvalidManager 错误没有方法签名:users.UserRole.save() 适用于参数类型:(java.util.LinkedHashMap) 值:[[flush:false, insert:true]] 可能的解决方案:wait()、any()、wait(long)、use([Ljava.lang.Object;)、 isCase(java.lang.Object),each(groovy.lang.Closure)
groovy.lang.MissingMethodException:没有方法签名:users.UserRole.save() 适用于参数类型:(java.util.LinkedHashMap) 值: [[刷新:假,插入:真]] 可能的解决方案:wait()、any()、wait(long)、use([Ljava.lang.Object;)、isCase(java.lang.Object)、each(groovy.lang.Closure) 在 users.UserRole.create(UserRole.groovy:32) 在 users.UserRole.create(UserRole.groovy) 在 users.UserRole$create.call(来源未知) 在 users.WorkgroupTests.testInvalidManager(WorkgroupTests.groovy:17)
集成中比单元测试更好地涵盖了这一点吗?我是否需要模拟 UserRole(如果需要,如何模拟?)?这些类型的测试通常是如何进行的?
I'm sure this is a fairly common situation. I'm using the Spring Security Core plugin and want to create a domain model that has a Person limited to certain roles:
class Workgroup {
Person manager
...
static constraints = {
manager(validator: {mgr ->
// it feels like there should be a more elegant, groovy way of doing this.
def auths = mgr.getAuthorities();
def returny = false
auths.each {
if(it.authority == 'ROLE_MANAGER')
{
returny = true
}
}
return returny
})
}
}
This test fails like a mofo:
void testInvalidManager() {
def nick = new Person(username:'Nick')
def nonManagerRole = new Role(authority:'ROLE_EMPLOYEE')
UserRole.create(nick,nonManagerRole)
def awesome = new Workgroup(name:'mooCows', manager:nick)
mockForConstraintsTests(Workgroup, [awesome])
assertFalse awesome.validate()
assertEquals "validator", awesome.errors["manager"]
}
testInvalidManager Error No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]] Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]]
Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
at users.UserRole.create(UserRole.groovy:32)
at users.UserRole.create(UserRole.groovy)
at users.UserRole$create.call(Unknown Source)
at users.WorkgroupTests.testInvalidManager(WorkgroupTests.groovy:17)
Is this better covered in Integration than Unit Testing? Do I need to mock UserRole (if so, how?)? How are these types of tests normally done?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
UserRole.create()
调用save()
,因此您需要使用mockDomain()
而不仅仅是mockForConstraintsTests()
代码>.但前提是您同意使用模拟测试域模型,而我永远不会这样做。在测试控制器或其他使用域类的类时,应该使用 Grails 中的模拟支持,但不应该为真正的持久性、创建数据库(甚至在内存中)等而烦恼。通过删除该依赖项,您将专注于当前层,相信其他层已经经过正确测试。但是,当您使用模拟来测试域类时,您实际上只是在测试模拟框架。因此,我总是对域类使用集成测试,以便它们针对真实的数据库运行。
为了回答代码示例中隐含的问题,我将约束写为
其大部分问题是,当常规 for 循环更可取时,您正在使用 every() ,因为您可以从 for 循环返回。仅当您确实想要在每个实例上调用闭包时才使用each()。下面的一个比另一个不那么好用,但使用了 for 循环:
UserRole.create()
callssave()
, so you need to usemockDomain()
instead of justmockForConstraintsTests()
.But that's only if you're ok with testing the domain model with mocks, which I would never do. The mocking support in Grails should be used when testing Controllers or other classes that use domain classes but shouldn't be bothered with real persistence, creating a database (even in-memory), etc. By removing that dependency you're concentrating on the current tier, trusting that the other tier is already properly tested. But when you use mocking to test domain classes, you're really just testing the mocking framework. So I always use integration tests for domain classes so they run against a real database.
To answer the implicit question from your code example, I'd write the constraint as
The issue with its bulk is that you're using each() when a regular for loop would be preferable since you can return from a for loop. Use each() only when you really want to invoke the closure on every instance. Here's one that's less groovy than the other one but uses a for loop: