Rollback transaction after @Test

131,126

Solution 1

Just add @Transactional annotation on top of your test:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"testContext.xml"})
@Transactional
public class StudentSystemTest {

By default Spring will start a new transaction surrounding your test method and @Before/@After callbacks, rolling back at the end. It works by default, it's enough to have some transaction manager in the context.

From: 10.3.5.4 Transaction management (bold mine):

In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener. Note that TransactionalTestExecutionListener is configured by default, even if you do not explicitly declare @TestExecutionListeners on your test class. To enable support for transactions, however, you must provide a PlatformTransactionManager bean in the application context loaded by @ContextConfiguration semantics. In addition, you must declare @Transactional either at the class or method level for your tests.

Solution 2

Aside: attempt to amend Tomasz Nurkiewicz's answer was rejected:

This edit does not make the post even a little bit easier to read, easier to find, more accurate or more accessible. Changes are either completely superfluous or actively harm readability.


Correct and permanent link to the relevant section of documentation about integration testing.

To enable support for transactions, you must configure a PlatformTransactionManager bean in the ApplicationContext that is loaded via @ContextConfiguration semantics.

@Configuration
@PropertySource("application.properties")
public class Persistence {
    @Autowired
    Environment env;

    @Bean
    DataSource dataSource() {
        return new DriverManagerDataSource(
                env.getProperty("datasource.url"),
                env.getProperty("datasource.user"),
                env.getProperty("datasource.password")
        );
    }

    @Bean
    PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

In addition, you must declare Spring’s @Transactional annotation either at the class or method level for your tests.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Persistence.class, SomeRepository.class})
@Transactional
public class SomeRepositoryTest { ... }

Annotating a test method with @Transactional causes the test to be run within a transaction that will, by default, be automatically rolled back after completion of the test. If a test class is annotated with @Transactional, each test method within that class hierarchy will be run within a transaction.

Solution 3

The answers mentioning adding @Transactional are correct, but for simplicity you could just have your test class extends AbstractTransactionalJUnit4SpringContextTests.

Solution 4

I know, I am tooooo late to post an answer, but hoping that it might help someone. Plus, I just solved this issue I had with my tests. This is what I had in my test:

My test class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "path-to-context" })
@Transactional
public class MyIntegrationTest 

Context xml

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="${jdbc.driverClassName}" />
   <property name="url" value="${jdbc.url}" />
   <property name="username" value="${jdbc.username}" />
   <property name="password" value="${jdbc.password}" />
</bean>

I still had the problem that, the database was not being cleaned up automatically.

Issue was resolved when I added following property to BasicDataSource

<property name="defaultAutoCommit" value="false" />

Hope it helps.

Solution 5

In addition to adding @Transactional on @Test method, you also need to add @Rollback(false)

Share:
131,126
Jan Vorcak
Author by

Jan Vorcak

Python quiz (found here) import re def blackbox(num): return not re.match(r"^1?$|^(11+?)\1+$", "1"*num)

Updated on July 08, 2022

Comments

  • Jan Vorcak
    Jan Vorcak almost 2 years

    First of all, I've found a lot of threads on StackOverflow about this, but none of them really helped me, so sorry to ask possibly duplicate question.

    I'm running JUnit tests using spring-test, my code looks like this

    @RunWith(SpringJUnit4ClassRunner.class)  
    @ContextConfiguration(locations = {})
    public class StudentSystemTest {
    
        @Autowired
        private StudentSystem studentSystem;
    
        @Before
        public void initTest() {
        // set up the database, create basic structure for testing
        }
    
        @Test
        public void test1() {
        }    
        ...  
    }
    

    My problem is that I want my tests to NOT influence other tests. So I'd like to create something like rollback for each test. I've searched a lot for this, but I've found nothing so far. I'm using Hibernate and MySql for this

  • Jan Vorcak
    Jan Vorcak over 11 years
    well, I tried this before, and it still doesn't work, maybe ... can the problem be that I didn't define the PlatformTransactionManager, how can I do that?
  • Tomasz Nurkiewicz
    Tomasz Nurkiewicz over 11 years
    @javo: how are you modifying the database? If you are using Jpa/Hibernate/JdbcTemplate/... there must be some PlatformTransactionManager. Otherwise how Spring will know about your transactions and database?
  • Adam Michalik
    Adam Michalik about 8 years
    That's exactly the opposite what the OP is asking for
  • DaveyDaveDave
    DaveyDaveDave about 8 years
    The link in this answer is no longer correct; see user2418306's answer below for the correct link and more context from the Spring documentation.
  • franta kocourek
    franta kocourek over 6 years
    Well, so you commit your statements manually? Are you sure your data was even written in your database?
  • Kamil Nękanowicz
    Kamil Nękanowicz about 6 years
    I does not work, each method requires a separate transaction, cant do it for whole class
  • Kamil Nękanowicz
    Kamil Nękanowicz about 6 years
    adding annotation '@Transactional' on class level does not work, adding annotation '@Transactional ' separately for each function works,and extends AbstractTransactionalJUnit4SpringContextTests works too
  • DerMike
    DerMike about 6 years
    This should have been a comment to the accepted answer.
  • Paulo Merson
    Paulo Merson about 6 years
    I'm testing an insert into a table. With @Transactional, the insert command is not even issued against the database (I can see that because the console has hibernate show-sql true). Works fine in many cases. But one of my tests checks that the database issues a DataAccessException because of a database constraint. In this case the test fails because the rollback happens "in memory" and the database is never called. Solution: use @Transactional at the @Test method level and not at the class level.
  • dan carter
    dan carter almost 6 years
    @PauloMerson you should have an '@After on any DB test classes that does a flush of the entity manager. This ensures the last DB operation gets pushed to the DB to allow constraints to fail, it will still rollback though
  • Joe Ernst
    Joe Ernst about 5 years
    For anyone struggling to understand Spring Transactions, make sure your data source is NOT set to auto-commit or you will drive yourself crazy trying to figure out why @Transactional seems to do nothing.
  • Dario Seidl
    Dario Seidl about 2 years
    This answers the opposite question, how not to rollback a transaction in a test. But it's still good to know, that's what I came looking for.