Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject dependencies in Grails Spock Specification test

I need to get the dependencies injected in my domain objects in my tests.

This tests are placed in the test/integration directory and extends from spock.lang.Specification.

How can I achieve this?

Note: I've seen this post How to inject spring beans into spock test, but it is not related with grails.

Edit:

The dependency I want to get injected is springSecurityService in my SecUser subclass called Player. The method that is failing is the encodePassword(), which is called in the beforeInsert().

I can mock this encodePassword() method in some tests, but when I want to test my controllers method save(), I can't mock the Player that is being created because it all happens inside the controllers method.

After changing to extend IntegrationSpec, this is my test code:

package intertigre.test.domain
import intertigre.domain.Fecha;
import intertigre.test.util.DomainFactoryTestService
import grails.plugin.spock.IntegrationSpec
import grails.test.mixin.TestFor

    @TestFor(Fecha)
    class FechaSpec extends IntegrationSpec{

    DomainFactoryTestService domainFactoryTestService = new DomainFactoryTestService()

    def 'test'(){
        given:
            def fecha = new Fecha()
        when:
            fecha.save()
        then:
            Fecha.get(1) == fecha
    }

}

I'm getting this exception when running grails test-app :spock:

java.lang.NullPointerException: Cannot get property 'mainContext' on null object
    at grails.plugin.spock.IntegrationSpec.$spock_initializeSharedFields(IntegrationSpec.groovy)

And this one when I run the test alone:

| Failure:  intertigre.test.domain.FechaSpec
|  java.lang.NullPointerException: Cannot get property 'autowireCapableBeanFactory' on null object
    at grails.plugin.spock.IntegrationSpec.setupSpec(IntegrationSpec.groovy:47)
| Failure:  intertigre.test.domain.FechaSpec
|  java.lang.NullPointerException: Cannot invoke method isActive() on null object
    at grails.test.mixin.support.GrailsUnitTestMixin.shutdownApplicationContext(GrailsUnitTestMixin.groovy:232)
    at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:176)
    at org.spockframework.runtime.extension.builtin.JUnitFixtureMethodsExtension$FixtureType$FixtureMethodInterceptor.intercept(JUnitFixtureMethodsExtension.java:145)
    at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:84)
    at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:176)
like image 768
Tomas Romero Avatar asked Aug 13 '12 04:08

Tomas Romero


2 Answers

Try declaring the springSecurityService into the test, as you would do in a controller. Grails is supposed to do all the job for you :)

For an integration test you do something like this:

package intertigre.test.domain
import intertigre.domain.Fecha;
import intertigre.test.util.DomainFactoryTestService
import grails.plugin.spock.IntegrationSpec

class DomainFactoryTestServiceSpec extends IntegrationSpec{

def domainFactoryTestService // you dont need to create a new instance, it's injected by spring

def 'test'(){
     given:
         // ...
     when:
         // ...
     then:
         // ....
 }

If you need to test a specific domain object (as your Fecha class), you probably need a unit test, something like this:

package intertigre.test.domain
import intertigre.domain.Fecha
import intertigre.test.util.DomainFactoryTestService
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification

@TestFor(Fecha)
@Mock([OtherObject1, OtherObject2])
class FechaSpec extends Specification {

def domainFactoryTestService // same thing here, if you need the service

def 'test'() {
     given:
         def fecha = new Fecha()
     and:
         def oo1 = new OtherObject1()
     when:
         // ...
     then:
         // ....
 }

You can use unit test to test services as well, it depends on what are you going to test (a class -the service- or a "situation" -the way the service is used-).

Ps. Of course, this code here hasn't been tested and can contain typos. :) But I hope you get my point about how to test.

like image 162
lucke84 Avatar answered Oct 07 '22 21:10

lucke84


Accepted answer above is good for unit tests of controllers that need service classes injected.

If you defined other spring managed beans in the resources.groovy and need them injected you can add this line at the top of your spec class

static loadExternalBeans = true //<-- loads resources.groovy beans

Source: http://grails.github.io/grails-doc/2.4.4/guide/testing.html#unitTesting

Adding static loadExternalBeans = true field definition to a unit test class makes the Grails unit test runtime load all bean definitions from grails-app/conf/spring/resources.groovy and grails-app/conf/spring/resources.xml files.

like image 37
dbrin Avatar answered Oct 07 '22 22:10

dbrin