I have a domain class which extends an abstract class which injects the spring security core plugin service.
class Extra extends WithOwner {
String name
}
abstract class WithOwner {
transient springSecurityService
User user
def getCurrentUser() {
return springSecurityService.currentUser
}
def beforeValidate() {
if(!user) {
user = getCurrentUser()
}
}
Boolean isLoggedUserTheOwner(){
return (user?.id == getCurrentUser()?.id)
}
}
I want to implement a controller test.
@TestFor(ExtraController)
@Mock([Extra, User, UserRole, Role])
class ExtraControllerTests {
void testEdit() {
def utils = new TestUtils()
def user1 = utils.saveUser1()
populateValidParams(params)
def extra = new Extra(params)
extra.user = user1
assert extra.save() != null
params.id = extra.id
def model = controller.edit() // Line 69
assert model.extraInstance == extra
}
}
If I run the above test I get:
test-app ExtraController.testEdit --unit --echoOut | Running 1 unit test... 1 of 1 --Output from testEdit-- | Failure: testEdit(com.softamo.movilrural.ExtraControllerTests) | java.lang.NullPointerException: Cannot get property 'currentUser' on null object at com.softamo.movilrural.WithOwner.getCurrentUser(WithOwner.groovy:8) at com.softamo.movilrural.WithOwner.isLoggedUserTheOwner(WithOwner.groovy:18) at com.softamo.movilrural.ExtraController.edit(ExtraController.groovy:39) at com.softamo.movilrural.ExtraControllerTests.testEdit(ExtraControllerTests.groovy:69) | Completed 1 unit test, 1 failed in 853ms
I have tried without success to mock the security service like this:
Extra.metaClass.springSecurityService = new MockSpringSecurityService(user1)
or even mocking the method
Extra.metaClass.getCurrentUser = { return user1 }
Any idea how could I work around this issue.
Grails 2.x supports defining spring beans for test environments using 'defineBeans' closure. It supports dependency injection in controllers etc, I am not sure if it works for domain objects as well. Theoretically it should be consistent across domain objects/controllers/services
See http://grails.org/doc/latest/guide/single.html#testing - The 'Testing Spring Beans' section.
This should work:
controller.springSecurityService = new SpringSecurityService()
If you want to mock getCurrentUser method in this service:
controller.springSecurityService.metaClass.getCurrentUser = { -> return user1 }
I'm not sure if you can ommit ->
in a line above, so test it. If you want to clear this mocked method after use or before another test case use this:
controller.springSecutiryService.metaClass = null
I found a great article about this problem: Inject springSecurityService Into Grails Domain Class for Controller Unit Testing
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With