0
votes

I'm migrating from grails 1.3.6 to 2.2.4. I'm currently having issues using withNewSession during an integration test. I've set up a demo project to more clearly represent the issue. Code Below:

class DomainA {
String id
String domainB
String description

static constraints =
{
    id unique: true, nullable:false
    domainB (nullable: false, blank:false,
    validator:{val, obj ->
        if(val != null)
        {
            DomainA.withNewSession{session ->
                def result = DomainB.findByDescription(val)
                if(result == null)
                {
                    return  'foreignkey'
                }
            }
        }

    })
}

static mapping =
{
    table 'DOMAIN_A'
    id column:'id', type: 'string', generator: 'assigned'
    version false
    domainB column:'DOMAIN_B'
}

}



class DomainB {

String id
String description

static constraints =
{
    id unique: true, nullable:false
    description nullable:false
}
static mapping =
{
    table 'DOMAIN_B'
    id column:'id', type: 'string', generator: 'assigned'
    version false
}
}

And the integration test

import static org.junit.Assert.*
import org.junit.*
class WithNewSessionTestTests extends GroovyTestCase{

@Before
void setUp() {
    DomainB b = new DomainB(description:"BEE")
    b.id = "B"
    b.save(flush:true, failOnError:true)
    DomainA a = new DomainA(domainB:"BEE", description:"EHH")
    a.id = "A"
    a.save(flush:true, failOnError:true)
}
@Test
void testSomething() {
    assertTrue true
}
}

The test fails when a tries to save. The error code coming back is 'foreignkey', which is what is returned when DomainA can't find an instance of DomainB. Debugging also shows me that the result value of DomainB.findByDescription(val) is null. Any ideas on how to get around this? I want my tests to continue to be transactional to avo

This test will succeed if I either remove withNewSession from the validation or if I set the test to static transactional = false. Any ideas on how to preserve both the withNewSession call and the transactional nature of the test?

Versions: Grails 2.2.4, Oracle 10+, Java 7.0.21, groovy 2.0.7

1
Hey, I am currently upgrading from Grails 136 to 224. Was this working fine in 136? Also whats the thought behind using NewSession vs using the same session in the validator? Will you not face the same issue at run time? - Karthick AK
It was working fine in 1.3.6. You don't get the issue at run time, only during integration tests. The reason I've been using withNewSession was to avoid hibernate flushing before the find is executed. Flushing while calling the custom validator creates an infinite loop/stack overflow error. - Joseph
Can you try wrapping domainB save with withTransaction{..}? - Karthick AK
Wrapping in withTransaction{...} doesn't change its behavior at all. - Joseph
Why isn't the Integration test class inheriting GroovyTestCase? - dmahapatro

1 Answers

0
votes

Change

    class DomainA {
String id
String domainB
String description
----- rest of the code
}

to

class DomainA {
String id
DomainB domainB
String description
}

In Integration Test

import static org.junit.Assert.*
import org.junit.*
class WithNewSessionTestTests extends GroovyTestCase{

@Before
void setUp() {
    DomainB b = new DomainB(description:"BEE")
    b.id = "B"
    b.save(flush:true, failOnError:true)
    DomainA a = new DomainA(domainB:b, description:"EHH")
    a.id = "A"
    a.save(flush:true, failOnError:true)
}
@Test
void testSomething() {
    assertTrue true
}
}

This should work.

Edit

From Grails Integration Test

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. Add a transactional property to your test class to check transactional behaviour:

 class MyServiceTests extends GroovyTestCase {
    static transactional = false
     void testMyTransactionalServiceMethod() {
         …
    } }

Be sure to remove any persisted data from a non-transactional test, for example in the tearDown method, so these tests don't interfere with standard transactional tests that expect a clean database.

Without static transactional = false then the test would have to persist to the db, and in integration test, data are rolledback and not persisted to the database.