I'm currently working on some integration (or functional, I'm not really a QA but back-end dev, so I might be sloppy with terms) REST tests for our project, we are using Grails 3.0.9, Spock Framework 1.0-Groovy-2.4 and PostgreSQL DB for testing.
Also we have separate DB for testing purposes, it is still crucial that changes are rolled back after each test. I have looked through Grails testing doc and was trying to use @Rollback
annotation as described in examples - and it is just not working, changes are still committed to DB.
As it is work project, I can't provide some real code snippets, hope you understand, although my test spec looks just like in the Grails doc example: extends from Specification
, @Integration
and Grails' @Rollback
annotations are used on class level.
import grails.transaction.Rollback
import grails.test.mixin.integration.Integration
@Integration
@Rollback
class SomeSpec extends Specification {
@Shared
RESTClient client
def setup() {
client = new RESTClient('http://localhost:8080')
}
I've tried everything: used @Rollback for each method separately, tried to use Spring's @Rollback
in the same way, also example was wrong about it - it can't be applied to class, only to methods, I've tried to use @Transactional
instead - no success.
Also I should mention that controller and services I'm using are annotated as Grails' @Transactional
, although removing all the annotations didn't change anything.
I've googled for the whole day and wasn't able to find anything useful as those solutions were mostly for Grails 2, so I believe my question is unique around SO. Some of those solutions suggested using IntegrationSpec instead of Specification, reporting it is working like intended, but it was removed for Grails 3 and replaced with @Integration
, so I believe that's not an option in my case.
I've also found numerous @Transaction
solutions, but those didn't help either, although there's a small chance I did something wrong while trying to apply those solutions.
So, currently the only option is to try to make test as independent of data as possible and to drop and re-create database after each test suite, but this is very poor solution IMO. I don't believe no one faced the same problem as I did, so I hope to find some acceptable solution. I'll gladly provide any missing information I forgot to mention, of course.
UPDATE: I've tried the workaround mentioned here - I've used Transactional, as I've described before, and it still has no effect, changes are still committed, although I get this pair of messages for each test, meaning it is actually trying to do something. Not sure it will be helpful, but here it goes (it is edited a bit):
INFO org.springframework.test.context.transaction.TransactionContext - Began transaction (1) for test context [DefaultTestContext@3dbe8e11 testClass = SomeSpec, testInstance = package.SomeSpec@5e2296ae, testMethod = $spock_feature_0_0@SomeSpec, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@6ec335b0 testClass = SomeSpec, locations = '{}', classes = '{class package.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.IntegrationTest=true}', resourceBasePath = '', contextLoader = 'grails.boot.config.GrailsApplicationContextLoader', parent = [null]]]; transaction manager [org.grails.orm.hibernate.GrailsHibernateTransactionManager@25870a3a]; rollback [true]
INFO org.springframework.test.context.transaction.TransactionContext - Rolled back transaction for test context [DefaultTestContext@3dbe8e11 testClass = SomeSpec, testInstance = package.SomeSpec@5e2296ae, testMethod = $spock_feature_0_0@SomeSpec, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@6ec335b0 testClass = SomeSpec, locations = '{}', classes = '{class package.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.IntegrationTest=true}', resourceBasePath = '', contextLoader = 'grails.boot.config.GrailsApplicationContextLoader', parent = [null]]].