Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a service injected in a domain class from a Controller Test Class?

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.

like image 763
Sergio del Amo Avatar asked Apr 23 '12 06:04

Sergio del Amo


3 Answers

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.

like image 127
Sudhir N Avatar answered Nov 19 '22 12:11

Sudhir N


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
like image 1
Tomasz Kalkosiński Avatar answered Nov 19 '22 14:11

Tomasz Kalkosiński


I found a great article about this problem: Inject springSecurityService Into Grails Domain Class for Controller Unit Testing

like image 1
Sergey Ponomarev Avatar answered Nov 19 '22 14:11

Sergey Ponomarev