Grails: grails-cucumber and compiled steps

I am finally finishing the precompiled steps support in the cucumber grails plugin.

Currently if we run grails test-app functional:cucumber it will fire up the whole application and then run cucumber. Cucumber will load, parse and execute all our groovy step source files. If there is an import missing in one of the source files (we will look at an example in a minute) it will throw an error at us. At runtime.

Compiling the cucumber glue code has the advantage that we can catch this already at compile time before grails runs the application. Depending on the size of your app this can save you a number of time consuming round trips.

Let’s take the grails-cucumber Book example and remove the BookController import from BookSteps.groovy.

//disabled the import below...
//import books.BookController
import data.Data

import static cucumber.api.groovy.EN.*

...
When (~'^I add "([^"]*)"$') { String bookTitle ->
    bookController = new BookController ()
    bookController.params << Data.findByTitle (bookTitle)
    bookController.add ()
}
...

The When step create a new BookController. Now if we run it with the current version of grails-cucumber (0.8.0) we will get the following output:

Prompt:Books hauner$ grails test-app functional:cucumber
| Environment set to test.....
| Packaging Grails application..
| Packaging Grails application.....
| Server running. Browse to http://localhost:8080/Books
| Compiling 2 source files.
| Error Compilation error compiling [cucumber] tests: startup failed:
/Users/hauner/Development/Grails/grails-cucumber.git/test/projects/Books/test/functional/steps/BookSteps.groovy: 12: unable to resolve class BookController 
 @ line 12, column 22.
       bookController = new BookController ()
                        ^

/Users/hauner/Development/Grails/grails-cucumber.git/test/projects/Books/test/functional/steps/BookSteps.groovy: 33: unable to resolve class BookController 
 @ line 33, column 22.
       bookController = new BookController ()
                        ^

2 errors
 (Use --stacktrace to see the full trace)

We can see that grails is packaging the application and starts the server, then cucumber starts loading the step code and fails as expected.

Now using the new precompiled steps feature it will look like this:

Prompt:Books_compile hauner$ grails test-app functional:cucumber
| Environment set to test.....
| Compiling 1 source files.
| Error Compilation error compiling cucumber glue code:
            startup failed:
/Users/hauner/Development/Grails/grails-cucumber.git/test/projects/Books_compile/test/cucumber/steps/BookSteps.groovy: 14: unable to resolve class BookController 
 @ line 14, column 22.
       bookController = new BookController ()
                        ^

/Users/hauner/Development/Grails/grails-cucumber.git/test/projects/Books_compile/test/cucumber/steps/BookSteps.groovy: 35: unable to resolve class BookController 
 @ line 35, column 22.
       bookController = new BookController ()
                        ^

2 errors
 (Use --stacktrace to see the full trace)

No packaging and no server startup before it fails. Cool ;-)

To use precompiled steps we only need to modify the plugin configuration a little bit. To make this more interesting I have also moved the step code to another directory to separate the feature description from the implementation.

The default layout I use in the Book examples has features and step code in the functional folder.

test
  \-- functional
        \-- data
              Data.groovy 
        \-- hooks
              env.groovy
        \-- steps
              BookSteps.groovy
        ListBooks.feature
        NewBook.feature

I changed the layout for the new Book_compile example to:

test
  \-- cucumber
        \-- data
              Data.groovy 
        \-- hooks
              env.groovy
        \-- steps
              BookSteps.groovy
  \-- functional
        ListBooks.feature
        NewBook.feature

I choose cucumber for the source files but it can by anything you like. Apart from the source directories we have to tell cucumber were it will find the (compiled) steps.

This will look like this (CucumberConfig.groovy):

cucumber {
     // steps, hooks etc that will be compiled
    sources = ["test/cucumber"]

    // .. and where cucumber will find the compiled steps & hooks
    glue = ["classpath:steps", "classpath:hooks"]
}

With the (new) sources directive we set the source directories and with the (existing) glue directive we tell cucumber where it will find the step code in the classpath by prefix the entries with classpath:.

In my original example the cucumber source files do not have a package name. This is bad for compiling the steps because we would have to tell cucumber to start searching for them at the default package. This is not a good idea because cucumber would check all .class files in the whole classpath to find the glue code.

It is better to properly package the step code so we can make sure cucumber will only look at classes it cares about.

In the example I have used multiple top level packages to show that it is possible. Usually you should place it under the same parent package so that there is only a single classpath: required for the configuration.

Note that we did not add the data path to glue. It is just a helper class that does not contain cucumber code, so we do not need to tell cucumber about it. If we add it, cucumber will ignore it.

test/functional

if you want to keep the source below test/functional that is ok too. You do not need to set it as sources in CucumberConfig.groovy but you still have to adjust the glue settings.

that’s it…

I hope you will like this new feature of grails-cucumber. I still have some cleanup todo before I will release it, but it is on its way.. :-)

Grails: JSONBuilder/render vs JsonBuilder

I had some fun creating a custom json in Grails. There is grails.web.JSONBuilder and groovy.json.JsonBuilder. The former seems to be deprecated (according to the grails documentation). But as it uses the same api to create json as the render method I looked at it anyway.

Both builder do create json but they are, let’s say unintuitive, when it it comes to arrays with nested objects. If you ask google a lot of people seem to fight with this as well. Often the answers are not enlightening either.

It looks like there is no other way than to read the docs … ;-)

How hard can it be?

This blog will show a number of simple examples that will hopefully help you understand JSONBuilder/render and JsonBuilder.

To concentrate on the json, the examples will be stripped of some boilerplate code and uses a few simple domain classes as test data:

JsonBuilder (groovy)

The examples are based on the following code snippets:

JsonBuilder json = new JsonBuilder ()
def map = json {
    ...
}

String result = json.toString ()

// json
{
  ....
}

 

JSONBuilder/render (grails)

JSONBuilder jSON = new JSONBuilder ()
JSON json = jSON.build {
    ....
}
String result = json.toString ()

// ... uses the same api as JSONBuilder without new,
// toString () and build
render (contentType: "text/json") {
    ....
}

 

  • to reduce the noise the examples will skip the new and the toString () lines
  • for easier reading the resulting json is formatted manually

 

Some of the examples use test data based on the following domain classes.

Example Domain Classes

class Artist {
    String name
}

class Song {
    String title
}

class Album {
    String title
    Artist artist
    static hasMany = [songs:Song]
    ....
}

 

Test Data Setup

Artist prettymaids = new Artist (name: "Pretty Maids")
Album motherland = new Album (title: "Motherland", artist: prettymaids)
motherland.addToSongs (new Song (title: "Mother of all Lies"))
motherland.addToSongs (new Song (title: "To fool a Nation"))
motherland.addToSongs (new Song (title: "Confession"))
motherland.addToSongs (new Song (title: "The Iceman"))

 

Now let’s look at some examples..

 

JsonBuilder (groovy)

 

an empty object

 

def map = json {
}

// json:
{}

 

simple properties

 

def map = json {
    title "Motherland"
    artist "Pretty Maids"
}

// json
{
    "title": "Motherland",
    "artist": "Pretty Maids"
}

 

simple nested object

 

def map = json {
    title motherland.title
    artist {
        name prettymaids.name
    }
}

// json
{
    "title": "Motherland",
    "artist": {
        "name": "Pretty Maids"
    }
}

 

The same result is also achieved by using named arguments.

def map = json {
    title motherland.title
    artist (name: prettymaids.name)
}

 

.. more simple nesting

 

We can combine named arguments with the property methods.

def map = json {
    title motherland.title
    artist (name: prettymaids.name, country: {
        name "Danmark"
    })
}

// json
{
    "title": "Motherland",
    "artist": {
        "name": "Pretty Maids",
        "country": {
            "name": "Danmark"
        }
    }
}

 

simple list

 

def map = json {
    list 1,2,3,4
}

// or...
def map = json {
    list ([1,2,3,4])
}

// json
{
    "list": [1,  2,  3,  4]
}

So far so good.

 

list with objects

 

Now it gets a little bit strange.. A property accepts a list as value as we have seen in the previous example. If we have objects in our list we can can create an argument list for the songs property by using the lists collect method and converting each object to a map.

def map = json {
    title motherland.title
    songs motherland.songs.collect { Song s ->
        [title: s.title]
    }
}

// json
{
    "title": "Motherland",
    "songs": [{
        "title": "To fool a Nation"
    }, {
        "title": "The Iceman"
    }, {
        "title": "Confession"
    }, {
        "title": "Mother of all Lies"
    }]
}

But why a map, I want to use the builder api!

We will have to write it like this to get the same output using the builder api:

def map = json {
    title motherland.title
    songs motherland.songs.collect { Song s ->
        json {
            title s.title
        }
    }
}

To create json for the nested objects (the songs) using the api we call the builder (json) again inside the collect closure. It will create the map for each song we have hand crafted in the above version.

We could also write:

def map = json {
    title motherland.title
    songs motherland.songs.collect { Song s ->
        songs {
            title s.title
        }
    }
}

using songs instead of json to call the builder. But I think that just adds to the confusion. In this case the inner songs seems to be ignored but if we call it something else, like songs2 we will get a song list and a simple song2 property with the last song as value.

I prefer the first version which is unintuitive enough. ;-)

As far as I understand the JsonBuilder there is no easier way to handle nested objects. Unfortunately it is not very user friendly.

I would like to write it like this:

def map = json {
    title motherland.title
    songs motherland.songs, {
        title s.title
    }
}

The builder would loop through motherland.songs and call the given closure to build each list items json.

 

JSONBuilder/render (grails)

 

Now a couple of similiar examples using grails.

 

an empty object

 

JSON json = jSON.build {
}

// json:
null

Using an empty json block in the render method will fail with a NullPointerException (in Grails).

 

simple properties

 

JSON json = jSON.build {
    title = motherland.title
    artist = prettymaids.name
}

// json
{
    "title": "Motherland",
    "artist": "Pretty Maids"
}

 

simple nested object

 

JSON json = jSON.build {
    title = motherland.title
    artist = {
        title = prettymaids.name
    }
}

// json
{
    "title": "Motherland",
    "artist": {
        "name": "Pretty Maids"
    }
}

 

list

 

JSON json = jSON.build {
    title = motherland.title
    songs = array {
        unused {
            title = "Mother of all Lies"
        }
        unused {
            title = "To fool a Nation"
        }
        unused {
            title = "Confession"
        }
        // or like this:
        _ {
            title = "The Iceman"
        }
    }
}

// json
{
    "title": "Motherland",
    "songs": [{
        "title": "To fool a Nation"
    }, {
        "title": "The Iceman"
    }, {
        "title": "Confession"
    }, {
        "title": "Mother of all Lies"
    }]
}

There are two things to note. First we can create lists with the explicit array method. Second the unused. We have to call a method on the builder to create the objects of the list, but this time the method name is not turned into a property name.

We can use anything here, it is just necessary so the closure can be called. Shortest and with fewest noise is probably to use _ {..} to create a list object.

Of course, we can use a loop to to create the song list:

JSON json = jSON.build {
    title = motherland.title
    songs = array {
        for (s in motherland.songs) {
            _ {
                title = s.title
            }
        }
    }
}

 

top level list

 

Now as the last example there is the weird create a list as top level element construct which goes like this:

JSON json = jSON.build {
    for (i in motherland.songs) {
        element ([title: i.title])  // parameters must be a map
    }
}

// or like this
JSON json = jSON.build {
    for (i in motherland.songs) {
        element {
            title = i.title
        }
    }
}

// json
[
    {"title":"The Iceman"} ,
    {"title":"Mother of all Lies"},
    {"title":"Confession"},
    {"title":"To fool a Nation"},
]

element is a special keyword here. Used at the top level it will create a list as the top level element.

This does not work in the render method by the way, it will create:

{
    "element": {
        "title":"To fool a Nation"
    }
}

 

That’s it.

 

You can get all (most) of this from the documentation. You may have to read it more than once though.. :-)

If you look after JsonBuilder you will find the api documention and at first sight an example that leaves some open questions. But it is all there in the api docs. Make sure you look at the additional examples of each method.

JSONBuilder and the render method are described in the Grails documentation: creating json, render and builder api.

JSONBuilder/renders explicit array method is a lot easier to understand than the collect expression we had to use with JsonBuilder, but the unused property on the list object in both builders is confusing from a user perspective.

Personally I prefer JsonBuilders notation. I only dislike the way we have to handle arrays. It would be a lot easier to understand if we could just write:

def map = json {
    songs motherland.songs, {
        title s.title
    }
}

 

Running git clone git@github.com:hauner/groovy-core.git groovy-core.git now …. :-)

Update: May 2014

My patch for the improved array handling was merged and is part of groovy 2.3.0.

Software Mythbuster

I just read the book The Leprechauns of Software Engineering from Laurent Bossavit. It talks about a a few common “facts” of software development that are not facts at all. They are just merely anecdotal. Unfortunately they are heavily used to support other claims.

These facts originate in some older papers that are referenced from other papers, which are referenced from other papers, which are…. I guess you get the idea.

By all this referencing the original information changed and also gained some kind of authority that is not justified.

Laurent tracked down the primary sources (listing the references) and their hypotheses. Showing that our “facts” are based on very limited data that magically gets generalized and that some papers used obscure metrics which compare apples and oranges.

The “facts” he dissects in details are the Cone of Uncertainty, 10x variation in software developers & cost of defects.

While I never thought of these “facts” and their pictures as “real facts” to the numbers (but more or less as some kind of trend) it is still surprising that their supporting data is so weak. We do not really know if the trends they describe are real or not. There is too less data to “verify” their claim even if they feel right.

Definitely an interesting read!

Escaping Fun: replaceAll (“\\\\”, “\\\\\\\\”)!

There is a small escaping bug in cucumber-jvm. The java generated groovy step snippets do not properly escape the escape character \ in the steps regular expression.

Currently it generates:

Given(~'^I have (\d+) cukes in my "([^"]*)" belly') { int arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}

which should be:

Given(~'^I have (\\d+) cukes in my "([^"]*)" belly$') { int arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}

Cucumber generates code snippets we have to escape the escape character in the snippet output too, i.e. the (\\d+). I have modified the groovy snippet generation before, so it should be an easy fix. Or so I thought. ;-)

It was not a big issue but it took me longer than expected to understand because escaping the escape characters is a bit confusing at first using replaceAll().

Escaping the escape character (\) gets interesting if it is a regular expression: it needs to be escaped again. All this endless escaping turns into this stupid piece of code:

public String escapePattern(String pattern) {
    return pattern.replaceAll ("\\\\", "\\\\\\\\");
}

The method above gets a regular expression string for a step as input (as I see it in the debugger):

"^I have (\\d+) cukes in my \"([^\"]*)\" belly$"

Actually the real string is just:

^I have (\d+) cukes in my "([^"]*)" belly$

And what we like to see as the final regular expression is:

^I have (\\d+) cukes in my "([^"]*)" belly$

We just want to replace \ with \\.

replaceAll takes a regular expression pattern (String) as the first parameter so we have to escape the \ twice to match it:

  • \ => \\ because \ is the escape character for regular expressions
  • \\ => \\\\ because \ is the escape character for Strings

Because \ is also a special character in the replacement (second) parameter of replaceAll. So we have to escape \ twice again:

  • \\ => \\\\ because \ is the escape character in the replacement parameter`
  • \\\\=> \\\\\\\\ because \ is the escape character for Strings

Which finally leads to this stupid line: pattern.replaceAll ("\\\\", "\\\\\\\\"); !

This can be simplified by using String.replace (CharSequence target, CharSequence replacement) (since 1.5). It does not use regular expressions which allows us to drop one level of escaping:

pattern.replace ("\\", "\\\\");

Which is a lot easier to understand. Which is also the final solution for the pull request :-)

Grails: Simple IP-Filter

Here are a few code snippets to show how easy it is to create an ip filter in Grails, i.e. allowing access only from specific remote addresses using just plain Grails code without any plugin.

Nothing fancy and more or less officially documented. Summarized here to remind myself how easy it is. :-)

The allowed ip addresses can be configured by a regular expression admin.ip using the grails standard configuration stuff. E.g. Config.groovy with a line like this: admin.ip = 192.168.1.2|192.168.1.5 to allow 2 ip addresses. The .s will be escaped automatically by the filter code.

package softnoise

import static org.springframework.http.HttpStatus.FORBIDDEN


class IpFilters {
    def grailsApplication

    def filters = {
        all (controller:'*', action:'*', controllerExclude:'allowed') {
            before = {
                def ips = getIpRegEx (grailsApplication.config)

                if (request.remoteAddr =~ ips) {
                    return true
                }

                response.sendError (FORBIDDEN.value ())
                false
            }
        }
    }

    private String getIpRegEx (def config) {
        config.admin.ip.replaceAll  ('\\.', '\\\\.')
    }

}

Here are a couple of unit tests for it using Spock. The third test just checks if the filter has excluded the allowed controller.

package softnoise

import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
import org.springframework.http.HttpStatus
import static org.springframework.http.HttpStatus.FORBIDDEN
import static org.springframework.http.HttpStatus.OK


@TestFor (GormController)
@Mock (IpFilters)
class IpFiltersSpec extends Specification
{
    static String VALID_REMOTE_ADDRESS = "162.168.1.2"
    static String INVALID_REMOTE_ADDRESS = "200.200.1.2"

    def setup () {
        grailsApplication.config.admin.ip = VALID_REMOTE_ADDRESS
    }

    def "reject access if the ip does NOT match the admin ip config" ()
    {
        given:
            request.remoteAddr = INVALID_REMOTE_ADDRESS

        when:
            withFilters (action:"index") {
                controller.index ()
            }

        then:
            HttpStatus.valueOf (response.status) == FORBIDDEN
    }

    def "allow access if the ip does match the admin ip config" ()
    {
        given:
            request.remoteAddr = VALID_REMOTE_ADDRESS

        when:
            withFilters (action:"index") {
                controller.index ()
            }

        then:
            HttpStatus.valueOf (response.status) == OK
    }

    def "allow access to 'allowed' controller from anywhere" () {
        given:
            request.remoteAddr = INVALID_REMOTE_ADDRESS

        when:
            withFilters (controller: 'allowed', action:"index") {
                controller.index ()
            }

        then:
            HttpStatus.valueOf (response.status) == OK
    }
}

Grails: named foreign keys

In Grails if we create a domain class with association we will get a foreign key for the association. Let’s see how the foreign key gets named using an example using a many-to-one association.

Here is a simple domain class with an association to itself.

package gorm

class Category {
    Category child
}

The create table for this class will look like this:

CREATE TABLE category (
    id bigint NOT NULL,
    version bigint NOT NULL,
    child_id bigint,
    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT fk302bcfeabee40a7 FOREIGN KEY (child_id)
        REFERENCES category (id)
)

I have removed some noise from the statement, so do not wonder if it looks a little bit different for you :)

We can see that the primary key gets a human readable name category_pkey but the name of the foreign key is fk302bcfeabee40a7. Not too readable. It would be nice if we could give the foreign key a human readable name too. What about <COLUMN>_<TARGET_TABLE>_fkey to make it similar to the name of the primary key?

It looks like Grails does not offer any GORM DSL sugar to customize the name of the foreign key. But naming it manually on each domain class may be a bit cumbersome anyway. It would be nice if we could make it use the <COLUMN>__<TARGET_TABLE>_fkey format automatically.

It turns out we can do this with a few lines of code. The basic idea is described in Customizing GORM with a Configuration Subclass using some Java code and a hardcoded foreign key.

Here is a version in groovy implementing the format given above:

package gorm

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
import org.hibernate.mapping.PersistentClass
import org.hibernate.mapping.ForeignKey


class GormConfiguration extends GrailsAnnotationConfiguration {
    boolean hasRenamedForeignKeys = false

    @Override
    protected void secondPassCompile () {
        super.secondPassCompile ()

        if (renamedForeignKeys) {
            return
        }

        renameForeignKeys ()
        renamedForeignKeys = true
    }

    void renameForeignKeys () {
        classes.values().each { PersistentClass persistentClass ->
            persistentClass.table.foreignKeyIterator.each {ForeignKey key ->
                key.name = createHumanReadableName (key)
            }
        }
    }

    String createHumanReadableName (ForeignKey key) {
        "${key.columns.first().name}__${key.referencedTable.name}_fkey"
    }
}

It is not perfect. We do not check the length of the generated name and there are are probably other details I do not know anything about yet we have to take care of. But it it a start. :-)

The create table now look like this:

CREATE TABLE category (
    id bigint NOT NULL,
    version bigint NOT NULL,
    child_id bigint,
    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT child_id__category_fkey FOREIGN KEY (child_id)
        REFERENCES category (id)
)

With a nicely named foreign key. :-)

What is left is to activate the code which is a one liner, we just have to add a configClass parameter to the datasource configuration:

    dataSource {
        configClass = gorm.GormConfiguration
        driverClassName = "org.postgresql.Driver"
        dialect = org.hibernate.dialect.PostgreSQLDialect
        dbCreate = "create"
        url = "jdbc:postgresql://localhost/gorm"
        username = "gorm"
        password = "gorm"
    }

That’s it.

Happy gorming :-)

Cucumber & Grails: Transaction Rollback

… the short version is: “the cucumber grails plugin will not provide automatic transaction rollback”.

After adding automatic rollback code in the cucumber grails plugin (version 0.5) and trying to use it I had to learn, that the automatic part is flawed and that it does not work in all cases.

I will try to explain why it does not work and how the cucumber plugin will deal with it. If you happen to know more about how Grails/Spring transactions work, please correct me where I am wrong. If you have to add something please do! :-)

First some background how Grails handles database transactions by default.

runtime

If we use Grails default settings, it will wrap any service call into its own transaction. If we make two service calls in a single controller action, each one will have its own transaction. We will take a look at a simple example to demonstrate the convention. See also the Services chapter in the grails documentation.

You can change the defaults, but changing them will not improve anything. It will just make the situation more complicated and therefore it does only supports the statement that we will not get automatic transaction rollback for functional testing. :-)

Reusing the plugins Book example and running grails (run-app) we can easily check this behaviour.

package books

class Book {
    String author
    String title

    static constraints = {
        title unique: true
    }
}

The service looks like this:

package books

class BookService {
    Book add (boolean error, Map params) {
        def newBook = new Book (params)
        newBook.save (failOnError: true)
        if (error) {
            throw new RuntimeException ("rollback!")
        }
        newBook
    }
}

To easily get an error when we want to, I have added a parameter to the add() method that tells the function to error.

The following controller code uses the service with code you should not write in real code. It is written like this to demonstrate grails transaction handling. You should use a single service call to make the action run with a single transaction.

Now when we run the multipleTransactions() action in the following controller:

package books

class BookController {
    def bookService

    def multipleTransactions () {
        params.author = "A1"
        params.title = "T1"
        bookService.add (false, params)

        params.author = "A2"
        params.title = "T2"
        bookService.add (true, params)
    }
}

… and look at the database (you can use the dbconsole to look into the h2 database) we will see a single row:

ID VERSION AUTHOR TITLE
1 0 A10 T10

After reading Services this should not be a big surprise. Both add() calls to the service get their own transaction. Because of the true parameter in the second call, it throws and error an grails will automatically rollback the transaction. But only the transaction of the second call. The transaction of the first call is already committed.

integration test

In integration tests grails does automatically wrap each test in a transaction and triggers a rollback when the test is finished (which by the way is the code I called to get the rollback in the plugin).

It just does not work in all cases.

It fails when we exercise the application with http requests. I assume because grails session/request code will run (which is not run in an integration test when we simply new the controller) using its own transaction code that is ignoring the transaction wrapped around the test (guessing here, I don’t yet understand what grails does in detail).

It also fails if we start to run code using withTransaction().

package books

class BookService {
    Book add (Map params) {
        def newBook
        Book.withNewTransaction {
            newBook = new Book (params)
            newBook.save (failOnError: true)
        }
        newBook     
    }
}

.. with the controller:

package books

class BookController {
    def bookService

    def transaction () {
        params.author = "A1"
        params.title = "T1"
        bookService.add (params)
    }
}

… and when we run two cucumber scenarios calling BookController.transaction () the second call will fail because of the unique constraint on the title. The withTransaction() part will not be rollbacked.

conclusion

So where does this information place us regarding rollback of database transactions in context of functional testing with cucumber? Although it is a play example it shows that transaction handling can already get complex in such a simple example. Now consider multiple request, service annotations that change the default behaviour or “manual” withTransaction() calls. It is not as easy as it looks.

Maybe it would work if we were able to intercept the creation of any transaction created by grails, always return the same transaction and rollback it when the test is finished.

Appart from not finding any information how this would work (maybe I didn’t use the correct search words) it does not look like a good idea. Although it sounds like a solution in the first moment, it will make grails behave differently in the test enviroment and the production environment. How big the difference is, is hard to say. It depends on how much you change grails default behaviour.

Anyway, it will behave differently and I think transactions are important enough that we do not want this when doing functional testing. When we run end to end, the transactions should be identical to production.

My conclusion is, that the transaction handling is complicated enough that the plugin can not handle this for us. Therefore it will no longer run grails transaction code automatically. We will have to take care of cleaning up the database by ourself. Either by completely dropping and re-creating the database schema before each test or by running some statements that will restore the database to its original state (I will write another article showing an example for both ways).

The plugin will still provide some simple configuration to enable the integration test rollback support. You can use it to get the automatic rollback when you build functional integration tests, e.g. you do not exercise the app using http requests and you don’t use withTransaction().