Grails 使用 Spring Security Core Plugin 测试用户角色自定义验证约束

Posted

技术标签:

【中文标题】Grails 使用 Spring Security Core Plugin 测试用户角色自定义验证约束【英文标题】:Grails testing user role custom validation constraints using Spring Security Core Plugin 【发布时间】:2011-08-16 05:22:33 【问题描述】:

我确信这是一种相当普遍的情况。我正在使用 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) 值:[[flush:false, insert:true]] 可能的解决方案: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(Unknown Source) 在 users.WorkgroupTests.testInvalidManager(WorkgroupTests.groovy:17)

集成比单元测试更能涵盖这方面的内容吗?我是否需要模拟 UserRole (如果需要,如何?)?这些类型的测试通常是如何进行的?

【问题讨论】:

【参考方案1】:

UserRole.create() 调用save(),因此您需要使用mockDomain() 而不仅仅是mockForConstraintsTests()

但前提是您可以使用模拟测试域模型,而我永远不会这样做。在测试控制器或其他使用域类的类时,应使用 Grails 中的模拟支持,但不应为真正的持久性、创建数据库(甚至在内存中)等问题所困扰。通过消除这种依赖关系,您将专注于当前层,相信另一层已经过适当的测试。但是当您使用模拟来测试域类时,您实际上只是在测试模拟框架。所以我总是对域类使用集成测试,以便它们针对真实数据库运行。

要回答代码示例中的隐含问题,我会将约束写为

static constraints = 
   manager validator:  mgr ->
      mgr.authorities.find  it.authority == 'ROLE_MANAGER'  != null
   

它的大容量问题是你使用 each() 时更可取的是常规 for 循环,因为你可以从 for 循环返回。仅当您真的想在每个实例上调用闭包时才使用 each()。这是一个比另一个不那么时髦但使用 for 循环的方法:

static constraints = 
   manager validator:  mgr ->
      for (auth in mgr.getAuthorities()) 
         if (it.authority == 'ROLE_MANAGER') 
            return true
         
      
      return false
   

【讨论】:

这肯定是另一个问题或 grails-user 讨论的主题,但你为什么不用mockDomain() 测试域类呢?例如,我的域逻辑包括几个 findBy*()s,与 parent.children.find 相反 - 为什么会不好?我对您的意见非常感兴趣,因为我知道您在 Grails 中的角色。 您应该使用 mockForConstraintsTests 测试域类,以验证您的域约束。否则,您可以使用 mockDomain 来提供类似于正确域对象的域对象,以便可以针对它们测试服务和控制器。

以上是关于Grails 使用 Spring Security Core Plugin 测试用户角色自定义验证约束的主要内容,如果未能解决你的问题,请参考以下文章

Grails - grails-spring-security-rest - 无法从 application.yml 加载 jwt 机密

使用 Spring Security Grails 插件编码密码

Grails + spring-security-core:用户登录后如何分配角色?

在 Grails 中使用 Pre/Post Spring-Security Annotations

Grails 3.0 和 Spring Security

Grails - 卸载 Spring Security Core