I have a very simple setup - a controller that invokes a method on a service. In this service, I save an object to the DB and also send a JMS message to a queue - once it is saved - using an injected JMSTemplate. The service has transactions enabled by default.
When testing this manually - with the ActiveMQ server down - an exception is thrown and the transaction is rolled back - with the net effect that the object is also not saved to the DB. All good.
However, when I run this through an integration test (with ActiveMQ still down), the assert, that I have in place to check that the object did not get saved in the DB using a count query after I invoke the controller, fails saying that the count is 1. I have confirmed that the DB does not have any of these objects when the test starts by adding another assert at the beginning of the test to ensure that the count is 0.
Is this expected behaviour (maybe due to the nature of transactions in an integration test environment) or am I potentially doing something wrong? The exception is still being thrown because the JMS server is down - and it is a RuntimeException.
Grails integration tests and transactions gives an impression that this is to be expected - in which case, are there any suggestions around best practices for how to test transactional behaviour in integration tests?
Not sure why everyone commented instead of answering as the comments do expose the answer. I'll jump in and try to snag the answer points!
Yes, in a Spock test the entire test, including whens, thens, givens, etc. are all run out of the same transaction. As such you will not see the rollback you are hoping for until after the completion of the test.
You can set your test to non-transactional by adding "static transactional = false" at the top of the test class. The fallout of course is that you will then need to clean up the database after your tests are run (if database sanitation is important to you). One big problem here is that the Grails IntegrationSpec class has a bug in it that will blow up whenever you try setting transactional to false. This SO has a solution to that problem:
Grails 2.3 IntegrationSpec cannot be transactional false
Basically, copy all of the code for grails.test.spock.IntegrationSpec into your own class and replace a few methods with versions that respect the transactional nature of the test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With