Search code examples
unit-testinggrailsconventions

Grails project setup and convention - testing a spring component that is not really a service


At first I have to say that I have more background with Spring than grails, and the later convention over configuration is a bit disturbing, when you don't have the cards.

Considering a grails project.

If I have a 'Component' (Spring term for a POJO that will be in the spring context) that is not really a service, but more a part of another object, where should I put it ? In the src/groovy or in grails/services ? It is looking like the second option give me more power for writing my tests and since Grails views Service as:

Services in Grails are the place to put the majority of the logic in your application

I feel like the grails/services dir is a kind of a bag for all Springified beans...

Next question, how can I unit test my Component/Service if I need some companions bean in the Spring context for that said Service. This companions are not services, but rather other components that are mandatory at runtime but for which I can use default implementations.

With spring I can simply use this kind of annotation to create a small context for my tests:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", 
                                    "/jobs/skipSampleJob.xml" })

How to do the same with Grails ? I want to know if there is a prefered way to create a small Spring context, that can be reused and composed, for the tests as I can do with the @ContextConfiguration annotation.

With all the hidden conventions of grails I fear to not use the right way (if one exists) but the lake of clear explanation about them drive me toward direct usage of Spring.


Solution

  • I have RTFM, and the answer was there, a little bit drowned in the middle of the page: http://grails.org/doc/2.0.x/guide/testing.html

    Testing Spring Beans

    When using TestFor only a subset of the Spring beans available to a running Grails application are available. If you wish to make additional beans available you can do so with the defineBeans method of GrailsUnitTestMixin:

    class SimpleController {
        SimpleService simpleService
        def hello() {
            render simpleService.sayHello()
        }
    }
    void testBeanWiring() {
        defineBeans {
            simpleService(SimpleService)
        }
    controller.hello()
    assert response.text == "Hello World"
    }
    

    The controller is auto-wired by Spring just like in a running Grails application. Autowiring even occurs if you instantiate subsequent instances of the controller:

    void testAutowiringViaNew() {
        defineBeans {
            simpleService(SimpleService)
        }
    def controller1 = new SimpleController()
        def controller2 = new SimpleController()
    assert controller1.simpleService != null
        assert controller2.simpleService != null
    }