Announcement Announcement Module
Collapse
No announcement yet.
SpringJUnit4ClassRunner: Rollback exception instead of Cause Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • SpringJUnit4ClassRunner: Rollback exception instead of Cause

    Hello,

    I use the SpringJUnit4ClassRunner JUnit test runner with Transactional tests (using the @Transactial annotation). The Tests access an in-Memory DB (H2) via Hibernate (JPA).

    Those test do commit @TransactionConfiguration(defaultRollback = false), as an in-memory DB is used and many issues would go unnoticed on rollback (as Hibernate is used in auto flush mode will not actually access the DB before unless it is forced to by a query).

    Now, everything works fine, but if an exception occurs in a test, the actuall cause is not visible. The only thing the Eclipse JUnit Runner (and the log of the Maven2 build) shows is:


    Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.Trans actionalTestExecutionListener@2c482c48] to process 'after' execution for test: method [public void ch.sbb.tip.service.core.CoreServiceTest.testDBPara meter()], instance [ch.sbb.tip.service.core.CoreServiceTest@3fa43fa4], exception [null]
    org.springframework.transaction.TransactionSystemE xception: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.springframework.orm.jpa.JpaTransactionManager. doCommit(JpaTransactionManager.java:465)
    at org.springframework.transaction.support.AbstractPl atformTransactionManager.processCommit(AbstractPla tformTransactionManager.java:709)
    at
    ....
    org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.main(RemoteTestRunner.java:196)
    Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.hibernate.ejb.TransactionImpl.commit(Transacti onImpl.java:51)
    at org.springframework.orm.jpa.JpaTransactionManager. doCommit(JpaTransactionManager.java:456)
    ... 23 more


    This is very anoying in daily work, as this Exception is completely uninterresting - the reason why the transaction was marked read only is the only thing I would be interrested in. I can of course catch the Exception in my JUnit test case and log it there... I tried to extend the SpringMethodRoadie, but its package private, so I would have to implement into a spring package.

    Does anyone have any hints how to solve this issue?

    kind regards,
    Florian

  • #2
    Hi Florian,

    Originally posted by fseidl View Post
    Those test do commit @TransactionConfiguration(defaultRollback = false), as an in-memory DB is used and many issues would go unnoticed on rollback (as Hibernate is used in auto flush mode will not actually access the DB before unless it is forced to by a query).
    I recommend that you autowire the Hibernate SessionFactory in your test class and then call sessionFactory.getCurrentSession().flush() from within your test methods. That will do two things for you:
    1. You don't have to configure the test class to commit transactions
    2. You can declare expected exceptions

    For an example, check out the HibernateSessionFlushingTests class that I recently added to the Spring test suite.

    Originally posted by fseidl View Post
    Now, everything works fine, but if an exception occurs in a test, the actuall cause is not visible. The only thing the Eclipse JUnit Runner (and the log of the Maven2 build) shows is:

    < snip >

    This is very anoying in daily work, as this Exception is completely uninterresting - the reason why the transaction was marked read only is the only thing I would be interrested in.
    The exception occurs as a result of the attempt to commit the transaction within TransactionalTestExecutionListener. Thus the entire stack trace is displayed from that point (i.e., beginning with the TransactionalTestExecutionListener). This is by design.

    Originally posted by fseidl View Post
    I can of course catch the Exception in my JUnit test case and log it there...
    You cannot catch the exception in your test method unless you flush the session as I mentioned above.

    Originally posted by fseidl View Post
    I tried to extend the SpringMethodRoadie, but its package private, so I would have to implement into a spring package.
    FYI: SpringMethodRoadie was an internal implementation detail of Spring 2.5.x. Furthermore, I removed SpringMethodRoadie in Spring 3.0 for compatibility with JUnit 4.5/4.6. Thus you certainly do not want to try anything with SpringMethodRoadie.

    Originally posted by fseidl View Post
    Does anyone have any hints how to solve this issue?
    Try out the manual session flushing technique and let me know if that solves your problem!

    Regards,

    Sam

    Comment


    • #3
      Thank you for your reply

      Hi Sam,

      Thank you very much for your reply. From your code I would say it can not solve my problem. I will test this, you know better and propably I am wrong.

      I do not expect those Exceptions, they are part of a test failing and failing for a reason. My only issue is that I do not see the actual reason for the failture in the log. Catching the Exception does definitely work if done within the Test method - there I can see and log the original Exception, which is what I need (its just that log entry I would require). If I do something like

      @Test @Transactional testSomething() throws Exception() {
      try {
      ..execute something..
      }
      catch(Exception ex) {
      ex.printStackTrace();
      throw ex;
      }
      }


      my issue is solved. For that specific method.

      But this is not really a good solution, is it? And I would need to do it for all tests within the project, which is ugly and quite an effort.

      The reason for the second exception is that the Transaction gets marked rollback only and then this is the only exception I get to see - it is not directly caused by the original one, so it is not in the stacktrace as well.

      Regards,
      Florian

      Comment


      • #4
        Hi Florian,

        Originally posted by fseidl View Post
        The reason for the second exception is that the Transaction gets marked rollback only and then this is the only exception I get to see - it is not directly caused by the original one, so it is not in the stacktrace as well.
        Could you please put together a small test case which reproduces the exact behavior you're seeing and attach it to a new JIRA issue describing the expected behavior?

        That would help us better investigate the problem and make sure we don't forget about it.

        Thanks,

        Sam

        Comment


        • #5
          Is there anyway to make this session flush automatic? Perhaps with an parameter to @TransactionConfiguration that causes spring to flush the tx before rolling it back?

          It is rather a pain to have to inject the entity manager into every SpringJunit4ClassRunner based integration test, and then, in every single test remember to call em.flush().

          It rather invalidates the whole rollback by default approach within the spring testing framework that you will get false positives unless you remember to flush the session.

          Comment

          Working...
          X