我有一些经常使用的帮助方法,用于将单元测试放入单独的文件中。例如,我的想法是允许我的XYZTests.groovy调用TestHelper.getUserObject()以获得完全初始化的User实例。
现在的问题是,在用户的springSecurityService.encodePassword(pw)
中调用beforeInsert()
总是失败,因为在TestHelper.groovy中没有模拟springSecurityService 。
java.lang.NullPointerException: Cannot invoke method encodePassword() on null object
User.groovy :
def beforeInsert() {
// ...
password = springSecurityService.encodePassword(pw)
// ...
}
注意:我想避免在 TestHelper.groovy中使用任何模拟,以便在集成测试中使用它的方法。
尽管如此,即使我试图在TestHelper.groovy中的任何地方调用mockFor()
,我也会得到一个MME:
No signature of method: static myproject.TestHelper.mockFor() is applicable for argument types: (java.lang.Class, java.lang.Boolean) values: [class grails.plugins.springsecurity.SpringSecurityService, true]
groovy.lang.MissingMethodException: No signature of method: static myproject.TestHelper.mockFor() is applicable for argument types: (java.lang.Class, java.lang.Boolean) values: [class grails.plugins.springsecurity.SpringSecurityService, true]
at myproject.TestHelper.mockSpringSecurityService(TestHelper.groovy:59)
at myproject.TestHelper$mockSpringSecurityService.callStatic(Unknown Source)
at myproject.TestHelper.getUserObject(TestHelper.groovy:47)
at myproject.TestHelper$getUserObject.call(Unknown Source)
at myproject.UserTests.setUp(UserTests.groovy:26)
注意:我目前正在嘲笑springSecurityService.encodePassword
:
// in UserTests.groovy
protected void setUp() {
// mockDomain(...) and such here
def u = TestHelper.getUserObject("Pummel")
u.springSecurityService = mockSpringSecurityService()
assert u.save()
}
private mockSpringSecurityService() {
def ssService = mockFor(SpringSecurityService,true)
ssService.metaClass.encodePassword() { password ->
"08a2d3c63bf9fc88276d97a9e8df5f841fd772724ad10f119f7e516f228b74c6"
}
ssService
}
请注意,当我将所有帮助程序直接移动到UserTests.groovy时,一切正常!
答案 0 :(得分:5)
解决方法是克制不要调用 TestHelper.groovy 中的任何user.save()
。
这是有道理的,就像许多(单元)测试一样,持久化(保存)的实例无论如何都是不必要的。
另一方面,许多案例实际上需要未保存的内容。 (例如,为了测试.save()
本身的某些效果)
集成测试的工作示例将是:
def user = TestHelper.getUserObject()
user.save()
对于单元测试:
def user = TestHelper.getUserObject()
user.springSecurityService = new SpringSecurityService() // or the described mock accordingly
user.save()
这可以防止任何模拟出TestHelper.groovy
答案 1 :(得分:2)
在TestHelper
中,您可以使用Groovy ExpandoMetaClass metaClass.static在SpringSecurityService上为encodePassword打一个模拟闭包:
SpringSecurityService.metaClass.'static'.encodePassword = {'08a2d3c63bf9fc88276d97a9e8df5f841fd772724ad10f119f7e516f228b74c6'}
我会把这个类放在src / groovy下的测试包中