35

I'm running a simple JUnit test agains an application DAO. The problem is that I always get:

javax.persistence.RollbackException: Transaction marked as rollbackOnly

The JUnit test is:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:com/my/app/context.xml"}
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public class PerformanceTest {

    @Test
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    @Rollback(false)
    public void testMsisdnCreationPerformance() {
        // Create a JPA entity

        // Persist JPA entity
    }
}

As you can see I'm declaring clearly not to rollback this method.

Does Spring JUnit support always sets rollback to true?

svick
  • 236,525
  • 50
  • 385
  • 514
Juan
  • 989
  • 1
  • 14
  • 22

7 Answers7

67

It should work, like you expect it, but may be you open another transaction within your class under test or you have an other feature/or bug somewhere.

Btw this annotations should be enougth:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:com/my/app/context.xml"}
@Transactional
public class PerformanceTest {

    @Test
    @Rollback(false)
    public void testMsisdnCreationPerformance() {
        // Create a JPA entity

        // Persist JPA entity
    }
}

@See Spring Reference Chapter 9.3.5.4 Transaction management (or current version)

Ralph
  • 118,862
  • 56
  • 287
  • 383
20

Just add annotation Rollback and set the flag to false.

   @Test
   @Rollback(false)
grep
  • 5,465
  • 12
  • 60
  • 112
9

It is strange to desire a test that changes your database and keep the modification. Tests are supposed to be orthogonal : no test depends on an other. Moreover, tests are supposed to be independent of tests order, and even idempotent.

So either you want to change you data base in your setUp() method and rollback the change in your tearDown() method, either you want to setup a test database with some good values in it for tests.

Maybe I am missing something here but usually you should not want that.

Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • 40
    But this is not the question. – Ralph Mar 22 '12 at 07:07
  • 12
    I got a really good reason why to not rollback a junit test. So then "right answer" is not that you shouldnt do it. The right answer is someone who can explain how. – user829237 Dec 11 '12 at 12:04
  • Could you please add some comment on how to add some data in set up method, still see it anywhere inside the code under test and then rollback it? – kboom Jul 29 '14 at 08:47
  • It depends so much on the database ! @kboom – Snicolas Jul 29 '14 at 17:09
  • 6
    Not answering the question. Some times you use junit functionality for various purposes. If someone asks I want to able to commit in junit - provide the answer how to do that, and then say it may not be best practice if it is true junit (repeatable testing). – Espresso Oct 03 '15 at 00:37
  • 1
    @SeanPatrickFloyd the hint is on REQUIRED_NEW, which indicates that he is obviously trying to set up a specific db state prior to executing his integration-tests. Therefore it needs to be persisted before the act part of the test. So yea, i think we should stick to answering the question. – Sheepy Dec 13 '16 at 05:16
6

From official Documentation:

By default, test transactions will be automatically rolled back after completion of the test; however, transactional commit and rollback behavior can be configured declaratively via the @Commit and @Rollback annotations

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html#integration-testing-annotations

@Commit indicates that the transaction for a transactional test method should be committed after the test method has completed. @Commit can be used as a direct replacement for @Rollback(false) in order to more explicitly convey the intent of the code.

harryssuperman
  • 465
  • 3
  • 7
  • What was very confusing to me is that the test would commit the txn even if exceptions bubble all the way up, where normally (@Transactional on business class as opposed to on test method) that would trigger a txn rollback. – Juan Bustamante Sep 01 '17 at 15:47
  • Only for checked Exceptions. Unchecked will be rolled back automat. https://stackoverflow.com/questions/3701376/rollback-on-every-checked-exception-whenever-i-say-transactional – harryssuperman Oct 27 '17 at 14:41
3
I use Junit5, both commit and rollback(false) works with me.

    @ExtendWith(SpringExtension.class)
    @SpringBootTest
    @Transactional
    public class MyIntegrationTest {

      @Test
      @DisplayName("Spring Boot Will Rollback Data, " +
      "Can Disable it By Add @Commit Or @Rollback(false) Annotation")
      //@Commit
      //@Rollback(false)
      public void test() throws Exception {
       //your test codes here...
      }
Vikki
  • 1,897
  • 1
  • 17
  • 24
0

I agree the Ralph's answer.

The Propagation.REQUIRES_NEW creates a new transaction and this probably does not match with the main transactional route in which the test is running.

In my simple experience the annotation @Transactional will properly work to define the transactional context in which every single test should run, delegating to this one the specific current Rollback clause (as shown by Ralph).

The Ralph's answer is useful and in the same time the Snicolas's answer concerns a particular case of managing context of tests. The idempotence is fundamental for integration and automatic tests, but should be different ways to implements them. The question is, which kind of methods do you have? And what behavior do theese methods have?

   [...]
   @Transactional

   public class Test {

   @Test
   @Rollback(false)
   public void test() {

   [...]

Is the simple, question-coherent way :)

AL3X
  • 61
  • 4
0
  1. add @Rollback on your Test class-level

  2. add @Transactional(value = "your_ManagerName",rollbackFor = Exception.class) on your test method

Daan Seuntjens
  • 880
  • 1
  • 18
  • 37
xaiweiyi
  • 161
  • 1
  • 4