How can you check the code of a transactional database?

Imagine you have some simple code where you insert two rows into a database in a single transaction.

How can you force the second to fail in the test to check that the first is being rolled back?

If it were a web service, I would laugh at the metaprogramming so that the second call doesn't get through.

But with the database code I'm not sure. Maybe there is some jdbc driver that throws exceptions (say for every 7th operation)?

ok let's be more specific:

Imagine you have some kind of legacy code. It's poorly structured, but you don't want to refactor it either (let's write some tests first!). There seems to be a problem with transactional behavior and you would like to test your code.

Since the code mostly works, it would be difficult to get it to work with errors due to limitations.

So in my tests, I would like to simulate what happens in the event of a database crash (possibly due to a deadlock, unavailability, disk full, or something like that) or when you "shut down".

+4


source to share


1 answer


The integration test would be a good place to test transactions and rollbacks. Something like this pattern should suffice:

package com.example

import grails.test.mixin.integration.Integration
import grails.transaction.*
import spock.lang.*
import org.springframework.beans.factory.annotation.Autowired

@Integration
@Rollback
class TransactionIntSpec extends Specification {

    @Autowired
    FooService service

    void "test transaction rollback"() {
        given: 'bar service throws exception'
        service = Mock(FooService) {
            serviceBar() >> { throw new Exception() }
        }

        when:
        service.serviceMethod()

        then:
        !Foo.count() && !Bar.count()
    }

    void "test transaction successfull"() {
        when:
        service.serviceMethod()

        then:
        Foo.count() && Bar.count()
    }
}

      

where Foo

and Bar

are just simple domain classes and the service class would look like this:



package com.example

import grails.transaction.Transactional

@Transactional
class FooService {

    def serviceMethod() {
        serviceFoo()
        serviceBar()
    }

    def serviceFoo() {
        new Foo().save(flush: true, failOnError: true)
    }

    def serviceBar() {
        new Bar().save(flush: true, failOnError: true)
    }
}

      

Tested in Grails 3.0.2

+1


source







All Articles