如何使用 grails 在单元测试中模拟 springSecurityService
Posted
技术标签:
【中文标题】如何使用 grails 在单元测试中模拟 springSecurityService【英文标题】:How to mock springSecurityService in unit tests using grails 【发布时间】:2014-06-23 03:28:55 【问题描述】:我在我的 grails 项目中使用 Spring 安全性。我已经安装了 spring-security-core 插件和 spring-security-ui 插件。
我用于 Person 和 Authority 的域类分别是 User 和 Role
根据项目要求,我修改了我的 User.groovy 类,代码如下:
class User
transient springSecurityService
//Mandatory Fields
String employeeId
String firstName
String lastName
String password
String emailId
//Other Fields
String mobileNumber
String address
String city
String zipCode
User manager
static hasMany = [previousPasswords: String]
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints =
employeeId blank: false, unique: true
firstName blank: false
lastName blank: false
password blank: false, password: true, validator: val, obj ->
if(obj.previousPasswords)
return !obj.previousPasswords.contains(encode(val.toUpperCase()))
return true
emailId blank: false, email: true
mobileNumber nullable: true
address nullable: true
city nullable: true
zipCode nullable: true
manager nullable: true
previousPasswords display: false, editable: false
static mapping =
password column: '`password`'
Set<Role> getAuthorities()
UserRole.findAllByUser(this).collect it.role as Set
def beforeInsert()
previousPasswords = [encode(password.toUpperCase())]
encodePassword()
def beforeUpdate()
if (isDirty('password'))
previousPasswords << encode(password.toUpperCase())
encodePassword()
protected String encode(String pwd)
return springSecurityService.encodePassword(pwd)
protected void encodePassword()
password = springSecurityService.encodePassword(password)
我正在尝试编写单元测试来检查这个单元类的约束
我的一个测试如下所示
void "test if employeeId can be blank or non-unique"()
given:
def springSecurityService = mockFor(SpringSecurityService,true)
springSecurityService.encodePassword()String pwd -> return null
// def springSecurityServiceFactory = mockFor(SpringSecurityService,true)
// def mockSpringSecurityService = Mock(SpringSecurityService)
// mockSpringSecurityService.metaClass.encodePassword = String password -> return null
// User.metaClass.encodePassword = return null
// User.metaClass.encode = password -> return null
// User.metaClass.getSpringSecurityService = mockSpringSecurityService
when: 'employeeId is blank'
def user = new User(employeeId: " ")
user.springSecurityService= springSecurityService
then: 'validation fails'
!user.validate()
user.errors.getFieldError("employeeId").codes.contains("nullable")
when: 'employeeId is unique'
user = new User(employeeId: "empId1", firstName: "f_name", lastName: "l_name", password: "password", emailId: "test@hptest.com")
user.springSecurityService= springSecurityService
then: 'validation succeeds'
user.validate()
user.save(flush: true, failOnError: true)
mockForConstraintsTests(User, [user])
when: 'employeeId is non unique'
def user_2 = new User(employeeId: "empId1")
user_2.springSecurityService= springSecurityService
then: 'validation fails'
!user_2.validate()
user_2.errors.getFieldError("employeeId").codes.contains("unique")
我一直在尝试不同的方法来模拟 springSecurityService 但似乎都失败了。谁能建议一种模拟此服务的方法。
目前我收到此错误。
groovy.lang.MissingMethodException: No signature of method: grails.test.GrailsMock.encodePassword() is applicable for argument types: (com.hp.bots.UserSpec$_$spock_feature_0_0_closure1) values: [com.hp.bots.UserSpec$_$spock_feature_0_0_closure1@18324cd]
at com.hp.bots.UserSpec.test if employeeId can be blank or non-unique(UserSpec.groovy:25)
如果我尝试将它作为集成测试运行(不进行模拟),该测试也会失败。我无法理解我哪里出错了。
【问题讨论】:
您将不得不调用 createMock 来生成模拟并分配给用户实例,并根据 mockFor 控件的需求记录 encodePassword 【参考方案1】:我猜如果你替换
springSecurityService.encodePassword()String pwd -> return null
与
springSecurityService.demand.encodePassword()String pwd -> return null
和
user.springSecurityService= springSecurityService.createMock() (grails 2.3.7)
and for user_2
您应该能够运行此测试。
您可以在此处查看更多文档。 http://grails.org/doc/2.3.7/guide/testing.html
【讨论】:
【参考方案2】:我通常通过使用将被调用的函数创建一个映射来模拟服务。我只会在有问题的服务上仅调用一个或两个简单函数并且不需要验证/跟踪这些调用时才推荐这种方法。在您的情况下,您给定的子句可能如下所示:
def springSecurityService = [encodePassword: password ->
return password
]
【讨论】:
可能还需要验证对 mock 上特定方法的调用,而 mockControl.verify 更适合以上是关于如何使用 grails 在单元测试中模拟 springSecurityService的主要内容,如果未能解决你的问题,请参考以下文章
单元测试控制器时无法模拟 Grails 服务方法 - MissingMethodException