15.2 Integration Testing 3.1.10

See the light - agile, industrial strength, rapid web application development made easy

(Quick Reference) # 15.2 Integration Testing - Reference Documentation Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari Version: 3.1.10 ## 15.2 Integration Testing Integration tests differ from unit tests in that you have full access to the Grails environment within the test. You can create an integration test using the create-integration-test command:
    $ grails create-integration-test Example
The above command will create a new integration test at the location `src/integration-test/groovy/<PACKAGE>/ExampleSpec.groovy`. Grails uses the test environment for integration tests and loads the application prior to the first test run. All tests use the same application state. #### Transactions Integration tests run inside a database transaction by default, which is rolled back at the end of the each test. This means that data saved during a test is not persisted to the database (which is shared across all tests). The default generated integration test template includes the Rollback annotation:

    import grails.test.mixin.integration.Integration
    import grails.transaction.*
    import spock.lang.*@Integration
    @Rollback
    class artifact.nameSpec extends Specification {    ...    void "test something"() {
            expect:"fix me"
                true == false
        }
    }
The `Rollback` annotation ensures that each test methods runs in a transaction that is rolled back. Generally this is desirable because you do not want your tests depending on order or application state. #### Using Spring's Rollback annotation In Grails 3.0 tests rely on `grails.transaction.Rollback` annotation to bind the session in integration tests. But with this approach the `setup()` and `setupSpec()` method in the test is run prior to the transaction starting hence you would see `No Hibernate Session found` error while running integration test if `setup()` sets up data and persists them as shown in the below sample:

    import grails.test.mixin.integration.Integration
    import grails.transaction.*
    import spock.lang.*@Integration
    @Rollback
    class artifact.nameSpec extends Specification {    void setup() {
            // Below line would throw a Hibernate session not found error
            new Book(name: 'Grails in Action').save(flush: true)
        }    void "test something"() {
            expect:
            Book.count() == 1
        }
    }
To make sure the setup logic runs within the transaction you have to move it to be called from the method itself. Similar to usage of `setupData()` method shown below:

    import grails.test.mixin.integration.Integration
    import grails.transaction.*
    import spock.lang.*@Integration
    @Rollback
    class artifact.nameSpec extends Specification {    void setupData() {
            new Book(name: 'Grails in Action').save(flush: true)
        }    void "test something"() {
            given:
            setupData()        expect:
            Book.count() == 1
        }
    }
Another approach could be to use Spring's @Rollback instead.

    import grails.test.mixin.integration.Integration
    import org.springframework.test.annotation.Rollback
    import spock.lang.*@Integration
    @Rollback
    class artifact.nameSpec extends Specification {    void setup() {
            new Book(name: 'Grails in Action').save(flush: true)
        }    void "test something"() {
            expect:
            Book.count() == 1
        }
    }
It isn't possible to make `grails.transaction.Rollback` behave the same way as Spring's Rollback annotation because `grails.transaction.Rollback` transforms the byte code of the class, eliminating the need for a proxy (which Spring's version requires). This has the downside that you cannot implement it differently for different cases (as Spring does for testing). #### DirtiesContext If you do have a series of tests that will share state you can remove the `Rollback` and the last test in the suite should feature the DirtiesContext annotation which will shutdown the environment and restart it fresh (note that this will have an impact on test run times). #### Autowiring To obtain a reference to a bean you can use the Autowired annotation. For example:

    …
    import org.springframework.beans.factory.annotation.*@Integration
    @Rollback
    class artifact.nameSpec extends Specification {    @Autowired
        ExampleService exampleService
        ...    void "Test example service"() {
            expect:
                exampleService.countExamples() == 0
        }
    }
#### Testing Controllers To integration test controllers it is recommended you use create-functional-test command to create a Geb functional test. See the following section on functional testing for more information. | Quick Reference (hide)