Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting a mock service into a domain class for a Grails unit test?

I am writing some Spock spec based unit tests under Grails 2.1.1. I'm having trouble getting springSecurityService injected into my domain object that is used by my unit.

This is what I have so far,

@Mock([SecUser])
@TestFor(FooService)
class FooServiceSpec extends Specification {

    def "test some stuff"() {
        given:
        def mockSecUserService = Mock(SecUserService)
        mockSecUserService.emailValid(_) >> { true }
        mockSecUserService.checkUsername(_) >> { null }
        service.secUserService = mockSecUserService

        def mockSpringSecurityService = Mock(SpringSecurityService)
        mockSpringSecurityService.encodePassword(_) >> { 'tester' }
        // FIXME this needs to be injected somehow

        def params = [
                email: '[email protected]',
                username: 'unittester',
                password: 'tester',
                password2: 'tester'
        ]

        when:
        def result = service.createUser(params)

        then:
        // test results
    }
}

So what happens is that my service being test throws a NullPointerException because the mockSpringSecruityService is not injected. The createUser call in my service validates some params and then creates a SecUser domain object.

The SecUser has the following service injected into it to support password encoding,

class SecUser {
    transient springSecurityService

What I can't figure out out is inject this service in way that it is available to the domain class. I know there are a few posts already relating to this subject but most of them assume the test can instantiate the domain object, but in my case the instantiation is part of the unit being testing.

I've tried the following in place of the FIXME,

defineBeans {
    mockSpringSecurityService(SpringSecurityService) { bean -> 
        bean.autowire = true
    }
}

But as a result I get the follow error,

| groovy.lang.MissingMethodException: No signature of method: grails.plugins.springsecurity.SpringSecurityService.call() is applicable for argument types: (java.lang.Class, skillz.GameAccountServiceSpec$_spock_feature_0_0_closure4_closure5) values: [class grails.plugins.springsecurity.SpringSecurityService, ...] Possible solutions: wait(), any(), find(), dump(), collect(), grep()

Any ideas?

like image 698
James McMahon Avatar asked Aug 08 '13 17:08

James McMahon


1 Answers

What I ended up doing as a work around is,

SecUser.metaClass.encodePassword = { null }

In my domain object encodePassword is the method that uses the springSecurityService bean. So if I understand this correctly, this just overwrites this method to do nothing (the method is a void).

I'd prefer to use the metaClass to faux inject the bean, but my attempt at

SecUser.metaClass.getSpringSecurityService = { mockSpringSecurityService }

Blows up with an NPE when encodePassword attempts to use SpringSecurityService.

I feel like this is a less than ideal work around, so I'd love for someone to give a less hacky answer.

like image 196
James McMahon Avatar answered Oct 18 '22 22:10

James McMahon