I’m starting a Grails project, and decided to use the Spock testing framework. Spock is a very nice way to write tests, and I recommend it highly.

Unit tests with Spock are very easy to write, and Spock’s UnitSpec class provides all of the mocking methods that you would expect to find in a Grails-centric testing framework, including mockDomain, mockForConstraintsTests, and friends.

Here’s one of my simple Spock unit tests for a domain object:

:::groovy
class CompoundInstanceSpec extends UnitSpec {

    def "finding the compound instance's primary name"() {
        setup:
        mockDomain(CompoundInstance.class)

        expect:
        !compoundInstance.primaryName
        compoundInstance.setupPrimaryName()
        compoundInstance.primaryName == name2.name
        compoundInstance.compoundNames.remove(name2)
        compoundInstance.setupPrimaryName()
        !compoundInstance.primaryName

        where:
        name1 = [name: 'name1', primary: false]
        name2 = [name: 'name2', primary: true]
        name3 = [name: 'name3', primary: false]
        compoundInstance = new CompoundInstance(compoundNames: [name1, name2, name3])
    }
}

When it came to integration-testing a Grails Controller, however, I ran into some problems. The first problem was that my Grails-generated controller code used the ValidationTagLib’s message() closure to place internationalized messages into flash scope. Unfortunately, neither Grail’s integration test environment nor Spock’s ControllerSpec class wire the messageSource object into the application context, so the test failed when the controller tried to place a ‘success’ message into flash scope:

:::groovy
flash.message = "${message(code: 'default.created.message',
	args: [message(code: 'compound.label', default: 'Compound'), 
		results.compoundInstance.primaryName])}"

The simple solution (assuming that you don’t need to test the content of the message) is to use MOP programming to override the controller’s message() closure in the test’s setup. The following example always returns “mockMessage” for the value of the message, and allows the test to proceed normally:

:::groovy
setup:
controller.metaClass.message = {args -> "mockMessage"}

A more complete solution would actually wire up the messageSource.




The second problem that I ran into was that the service called by my controller needed to access the currently logged-in user (I’m using the spring-security plugin). When this is being done in the scope of a test, there is, of course, no currently logged-in user, and of course, the test would fail.

The simple solution for this problem is to wrap the body of the test with the SpringSecurityUtils’ doWithAuth closure, specifying the username of the user under whose authorization you wish to run the test. Of course, you’ll have to make sure that you either create the user and authorizations (roles) in BootStrap.groovy, or in the test setup.



Here, then, is my integration test with both issues handled:

Notice the ‘message’ fix at line 8, and the ‘security’ fix beginning at line 15