Announcement Announcement Module
No announcement yet.
integration testing and exceptions/rollbacks Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • integration testing and exceptions/rollbacks

    I'm fairly new to Spring, and I'm trying to get integration testing working using AbstractTransactionalSpringContextTests, and I'm having problems figuring out how to test rollbacks.

    Here is my understanding of how to use Spring's integration testing support:

    - I can populate my database with data for the test in onSetUpInTransaction, and it will be rolled back after the test.
    - Spring keeps my @Transactional methods from actually committing data to the database
    - After my @Transactional methods are called (after I run the method to test), I can then test the data in the database within the same transaction
    - When the test is done, Spring rolls the transaction back, leaving the database as it was before the test case started.

    My problem is that when the method I'm testing throws an exception, Spring just marks the transaction for rollback, but doesn't actually do anything until after the test finishes, so when I test the data, it hasn't been rolled back yet, and the test fails.

    Here's what the logs say:

    2007-06-22 16:04:28,558 [main] DEBUG  - Retrieved value [[email protected]] for key [[email protected]] bound to thread [main]
    2007-06-22 16:04:45,936 [main] DEBUG org.springframework.transaction.interceptor.TransactionInterceptor  - Completing transaction for [com.blah.CommunityManager.resendInvitations] after exception: java.lang.IllegalArgumentException: CommunityManager.resendInvitations() - invalid invitation
    2007-06-22 16:04:45,936 [main] DEBUG org.springframework.transaction.interceptor.RuleBasedTransactionAttribute  - Applying rules to determine whether transaction should rollback on java.lang.IllegalArgumentException: CommunityManager.resendInvitations() - invalid invitation
    2007-06-22 16:04:45,936 [main] DEBUG org.springframework.transaction.interceptor.RuleBasedTransactionAttribute  - Winning rollback rule is: null
    2007-06-22 16:04:45,936 [main] DEBUG org.springframework.transaction.interceptor.RuleBasedTransactionAttribute  - No relevant rollback rule found: applying superclass default
    2007-06-22 16:04:45,936 [main] DEBUG org.springframework.orm.hibernate3.HibernateTransactionManager  - Participating transaction failed - marking existing transaction as rollback-only
    2007-06-22 16:04:45,951 [main] DEBUG org.springframework.orm.hibernate3.HibernateTransactionManager  - Setting Hibernate transaction on Session [[email protected]] rollback-only
    2007-06-22 16:05:16,507 [main] DEBUG  - Retrieved value [[email protected]] for key [[email protected]] bound to thread [main]
    At first I thought maybe I should call endTransaction() if an exception is thrown, so that the transaction is actually rolled back, but my test data was set up inside that same transaction, so it would be rolled back also.

    What I'd like to do is be able to see that the data still looks like it did just before the method I'm testing gets called, but I don't see any way to do that, because the setup before the method and the method are really executing in a single transaction. There's no way to roll back just what the method did.

    I guess I'd be ok with some other way of determining that the transaction is going to be rolled back. Is there a way to ask Spring if the exception will cause the transaction to rollback?

    Anyway, I'm hoping someone can point me in the right direction on how to test rollbacks when an exception is thrown. Thanks in advance!


  • #2
    My own opinion, so feel free to reject this, but it seems to be that you're mixing two different things in the one test. I believe you should separate test setup from the actual test (which is why JUnit/TestNG both have ways to setup tests).

    Here's what I'd recommend - in your test setup - insert your data into the database, this can simply done without a transaction and committed. Then, when your test fires up and you call endTransaction() after the exception, the only db operations that get rolled back will be those conducted by the code you're testing. Finally, in your test teardown method you can delete that test data you created at setup.

    By the way, if you find doing this cumbersome, consider using DBUnit to setup and teardown your test data.


    • #3
      I can certainly see your point. Thanks for the response.

      I guess I read too much into it when I looked at the docs. It seemed to me that the big win was that you could set up and run your test and not have to explicitly tear everything down.

      That's what seemed so slick about the whole thing - every test starts with a clean database, with no cleanup required after the test. If I already have to tear down my test case setup, not having to tear down the results of running the test seems like a very small win.

      Also, calling endTransaction on an exception still seems error prone, because not every exception causes spring to rollback the transaction (only runtime by default, and it's configurable), so I still don't know if the transaction is really going to rollback when running in production.

      I just looked around, and it seems that the test class has an instance variable transactionStatus, which I can call isRollbackOnly() on, to see if the exception will cause spring to rollback. I think that's the missing piece. It seems to be working.

      Thanks for the help, ishaaq.