Inject dependencies in Grails Spock Specification test
Asked Answered
M

2

12

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)
Marquetry answered 13/8, 2012 at 4:35 Comment(4)
@AutoWired, maybe? Is your grails application running when you run your tests?Apothegm
Maybe it's a better idea to mock these dependencies? What dependencies are not injected? Write some example code to show a problem.Lonilonier
I've never tried using @Autowired in Grails, I will try it. I'm not running the app when I run the tests.Marquetry
I've updated my question with more data, I will add code laterMarquetry
B
12

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.

Bunin answered 14/8, 2012 at 13:12 Comment(7)
I'm actually extending Specification instead of IntegrationSpec. When I try to change to extend IntegrationSpec, I get the following exception when running the tests: java.lang.NullPointerException: Cannot get property 'mainContext' on null object at grails.plugin.spock.IntegrationSpec.$spock_initializeSharedFields(IntegrationSpec.groovy)Marquetry
You should extend IntegrationSpec while doing an integration test code.google.com/p/grails-spock-examples/wiki/… Is there a point where you declare that null mainContext? Which version of the spock plugin are you currently using? Can you add a piece of code to have a look at?Bunin
I'm using plugin ":spock:0.6". I never declare mainContext as a variable. I've updated the question with my test codeMarquetry
I think your mixing up unit tests and integration tests. An integration test is not meant to test a domain class (with the testfro annotation), but a service or a bunch of utils (like named queries). Anyway, I'm going to edit my answer trying to use the code you added to the question.Bunin
Later I will upload a controllerSpec code that is giving me the same problem. Should I use unit tests here to?Marquetry
Based on the code you posted, I was ablt to correct my controller spec. The error I was having was that I was using @TestFor(JugadorControllerSpec)Marquetry
Glad this was useful for you :)Bunin
O
1

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.

Obscure answered 17/12, 2015 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.