Fork me on GitHub

LD.

Music, software, life… and stuff.

[ Twitter ] [ GitHub ] [ Linked In ]

Dealing with common test support across test types

Grails ships with several different test superclasses to make your testing life easier. This is great, but what if you have your own common testing bits that you want to provide in a superclass? Even worse, what if you are using the Spock plugin and have a completely different class hierarchy to work with?

The current project I am working on has a mix of Spock and JUnit tests of different types. Most of the tests also require some relatively common context establishment regardless of the test type. The solution I came up with was to use a test support object instead of a super class. That might seem straightforward, but it gets interesting when you need dependency injection.

Let’s take a look at the test support class…

import org.codehaus.groovy.grails.commons.ApplicationHolder

class TestSupport { 
    
    @Lazy fixtureLoader = getBean('fixtureLoader')
    @Lazy someOtherService = getBean('someOtherService')
    
    protected getBean(name) {
        ApplicationHolder.application.mainContext[name]
    }
    
    def loadFixture(fixtureParams) {
        // load fixture here
    }
    
    // Other common methods and stuff
}

Why the use of ApplicationHolder to get at the application context and the beans? Well, we are trying to avoid mixing test and production code by having the TestSupport class in tests/integration, which means we can’t make it a service. We also can’t selectively create an autowired instance via grails-app/conf/resources.groovy because classes in tests/integration are not available to the classloader that deals with loading the application context. So while the use of the static holder bothers me, it’s the only tool we have to get the job done at the moment. Also, not the use of Groovy’s @Lazy transformation.

Here is how I use the test support class in a Spec…

import grails.plugin.spock.*

class SomeSpec extends IntegrationSpec {
    
    @Delegate TestSupport testSupport = new TestSupport()
    
    def "some stuff should happen"() {
        given:
        loadFixture(/* fixture options */)
        when:
        someOtherService.doStuff()
        then:
        someOtherService.stuffHappened
    }
    
    def "some other stuff should happen"() {
        given:
        loadFixture(/* fixture options */)
        when:
        someOtherService.doOtherStuff()
        then:
        someOtherService.otherStuffHappened
    }
}

The use of Groovy’s @Delegate transformation makes the actual test code look like it’s using a support superclass, but it isn’t, which is the whole point of this exercise. You can now use your common test support methods in any kind of test case.

Posted: Feb 16th, 2010 @ 1:08 pm

Tags: #grails  #software  

Comments

Archive · RSS · Theme by Autumn