Grails mockFor values not returned in controller

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Grails mockFor values not returned in controller

virtualpt
Hi All,

I am struggling to get up to speed with Grails, as I am very TDD focussed and the documentation on mocking in Grails seems a bit sparse ;-)

I am injecting a mock springSecurityService into my controller, but it is not behaving as I expect - I'm susre I'm just making a simple dumb mistake here, but have been trawling the net for hours and getting nowhere :-(

Many thanks in advance for any help :-)

Paul

The problem is that the springSecurityService.loggedIn call in my controller is returning false despite the mock saying return true (in fact none of these mocked methods are returning what I think they should). Here is the mock setup code from my test method

GrailsMock mockSpringSecurityService = mockFor(SpringSecurityService)
    mockSpringSecurityService.demand.encodePassword() {-> return "encrypted"}
    mockSpringSecurityService.demand.reauthenticate() { }
    mockSpringSecurityService.demand.loggedIn() {-> return true}
    mockSpringSecurityService.demand.principal() {-> return ["username":"Bob"]}
    mockParams.id = 1
    mockParams.password = "changed"
    mockParams.username = "Bob"
    controller.springSecurityService = mockSpringSecurityService.createMock()

    controller.update()
Reply | Threaded
Open this post in threaded view
|

Re: Grails mockFor values not returned in controller

burtbeckwith
I tend to a Map of Closures for mocking services in controllers since they're declared as "def fooService", so there's a lot of flexibility in what you can use there:

controller.springSecurityService = [encodePassword: { String p -> "encrypted" },
                                    reauthenticate: { String u -> },
                                    isLoggedIn: { -> true },
                                    getPrincipal: { -> [username: "Bob"]}]

But I think the issue with your mock is that all of the demands are specified incorrectly.

encodePassword() takes either a String or a String and an Object (the salt), so that one would be

   mockSpringSecurityService.demand.encodePassword() { String p -> "encrypted" }

reauthenticate() takes one or two params, so that would be

   mockSpringSecurityService.demand.reauthenticate() { String u -> }

loggedIn is actually a call to getLoggedIn(), so that'd be

   mockSpringSecurityService.demand.getLoggedIn() { -> true }

and likewise principal is a call to getPrincipal(), so that'd be

   mockSpringSecurityService.demand.getPrincipal() { -> [username: "Bob"] }

Burt

>
> Hi All,
>
> I am struggling to get up to speed with Grails, as I am very TDD focussed
> and the documentation on mocking in Grails seems a bit sparse ;-)
>
> I am injecting a mock springSecurityService into my controller, but it is
> not behaving as I expect - I'm susre I'm just making a simple dumb mistake
> here, but have been trawling the net for hours and getting nowhere :-(
>
> Many thanks in advance for any help :-)
>
> Paul
>
> The problem is that the springSecurityService.loggedIn call in my controller
> is returning false despite the mock saying return true (in fact none of
> these mocked methods are returning what I think they should). Here is the
> mock setup code from my test method
>
> GrailsMock mockSpringSecurityService = mockFor(SpringSecurityService)
c>     mockParams.id = 1
>     mockParams.password = "changed"
>     mockParams.username = "Bob"
>     controller.springSecurityService =
> mockSpringSecurityService.createMock()
>
>     controller.update()
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Grails mockFor values not returned in controller

virtualpt
Thanks Burt - you are a star, I really appreciate your help :-)

I can get it to work with the Map of closures, but this doesn't give me the confidence I need as I need to verify whether (some of) these methods were called. I guess I can just put asserts in the closure, but as a long time user of EasyMock (not so easy) and Mockito, I am used to using the frameworks to verify.

I have tried both mockSpringSecurityService.demand.getLoggedIn() {-> true} and mockSpringSecurityService.demand.isLoggedIn() {-> true}, but I still get 'junit.framework.AssertionFailedError: verify[1]: expected 1..1 call(s) to 'isLoggedIn' but was called 0 time(s).'

Any ideas?

Thanks

Paul
Reply | Threaded
Open this post in threaded view
|

Re: Grails mockFor values not returned in controller

virtualpt
For anyone else struggling with this. Methods & properties seem to behave quite differently when using mockFor. I confirmed this using Groovy MockFor - see code at the end to see what I tried. Anyway the only way so far I've found to solve this is to test by binding values to the closures which I can verify at the end of the method. I guess I could change the controller code to call the methods instead of using properties, which might be nicer as it would render it more easily testable. I hope that this is useful for someone and/or that some Groovy/Grails wizard can explain to me what is going on :-)

Paul

 def encodePasswordCount = 0
    def encodePasswordClosure = { String p, Object salt ->
                                  encodePasswordCount++
                                  "encrypted" }
   
    def reauthenticateCalled = false
   
    controller.springSecurityService = [encodePassword: encodePasswordClosure,
                                    reauthenticate: { String u -> reauthenticateCalled = true},
                                    loggedIn: true,
                                    principal: [username:"Bob"]]

    controller.update()
    assertEquals "show", redirectArgs.action
    assertEquals 1, redirectArgs.id
    assertTrue "reauth should be called", reauthenticateCalled
    assertEquals "encode not called correct number of times", 1, encodePasswordCount


GroovyConsole test using MockFor:
import groovy.mock.interceptor.*

class Mine {

    boolean isLoggedIn(){
        true;
    }
   
}

def m1 = new Mine()

println m1.loggedIn

def m2 =new MockFor(Mine)
m2.demand.isLoggedIn() {-> false}

m2.use{
    println m2.loggedIn
}

groovy.lang.MissingPropertyException: No such property: loggedIn for class: groovy.mock.interceptor.MockFor