hudi
hudi

Reputation: 16555

How to rollback test

Here's my test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:repositoryContextTest.xml" })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class SeasonITest {
@Autowired
private SeasonDao seasonDao;

@Test
public void createSeason() throws Exception {
    Season season = new Season();
    season.setName("2012");
    seasonDao.createSeason(season);
}

and the dataSource in my bean configuration file

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/tournament_system" />
    <property name="username" value="root" />
    <property name="password" value="root" />
    <property name="defaultAutoCommit" value="false"/>
    <property name="poolPreparedStatements" value="false"/>
    <property name="maxOpenPreparedStatements" value="0"/>
 </bean>

<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

When I run this test there a new record is created in my database.

How can I rollback this transaction?

This is the log output I see:

2012-06-15 15:00:02,173 [main] INFO  - ionalTestExecutionListener - 
 Rolled back transaction after test execution for test context 
 [[TestContext@76db09 testClass = SeasonITest, 
   locations = array<String>['classpath:repositoryContextTest.xml'], 
   testInstance = org.toursys.repository.dao.SeasonITest@1265109, 
   testMethod = createSeason@SeasonITest, testException = [null]]]

UPDATE:

all answers below want to change logic or database engine what I dont want. So I am offering reputation point to the right answer:

Why when I have this: @TransactionConfiguration(defaultRollback = true) in transaction configuration tests are not rolled back and how I can fix it ?

Upvotes: 5

Views: 9390

Answers (9)

Daniel Alexiuc
Daniel Alexiuc

Reputation: 13240

Your Dao needs to be marked @Transactional.

Also annotate your test with:

@TestExecutionListeners(TransactionalTestExecutionListener.class)  //Rolls back transactions by default

Upvotes: 0

Nirmal
Nirmal

Reputation: 4829

Try with following method after your test case logic.

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Upvotes: 0

Roy Kachouh
Roy Kachouh

Reputation: 1903

On the surface, your code and configuration looks correct. However, could you please post your SeasonsDAO object. We would first need to verify that the SeasonsDAO is correctly configured for transactions.

SeasonsDAO needs to be participating in the same TransactionContext as your test case and there is no way to verify that with the code you posted.

Did you mark SeasonsDAO as @Transactional ?

If it is not, I am not sure how the TransactionProxyFactoryBean would be able to proxy and declaratively manage the transaction.

At a high level, spring uses the notion of proxying to perform many services such as transaction management.

If you mark something as @Transactional, Spring will dynamically create a proxy that will implement the same interfaces as your target class. Once it is proxied, a transaction interceptor will wrap method calls to your target class and decide whether to rollback or commit based on defaults or rules that you may specify.

Upvotes: 1

lucrussell
lucrussell

Reputation: 5160

  • Try extending AbstractTransactionalJUnit4SpringContextTests
  • Note that MySql MYISAM tables are not transactional, you need to use INNODB type tables (see here and here)
  • Is your DAO also marked with @Transactional? This could cause a problem (see here)

Upvotes: 0

nook
nook

Reputation: 2396

Haha had this same thing happen to me like 3 days ago. Try adding transactionManager ="transactionManager" to your @contextConfiguration:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:PersistenceHelper-context.xml"})
@TransactionConfiguration(defaultRollback = true, transactionManager = "transactionManager")
@Transactional

Also, I am not 100% percent sure on this, but your XML file should follow the "*-context" format. Let me know if you would like to see my PersistenceHelper-context.xml file.

Upvotes: 0

Josef Prochazka
Josef Prochazka

Reputation: 1283

try to annotate the test method with @Transactional

Upvotes: 0

Java SE
Java SE

Reputation: 2073

Please make sure you must need to declare:

<tx:annotation-driven transaction-manager="transactionManager" /> 

in your spring configuration file e.g. (applicationContext.xml).

As @Lieber already explained but more explanation is: MySQL Server (version 3.23-max and all versions 4.0 and above) supports transactions with the InnoDB transactional storage engine. InnoDB provides full ACID compliance. See Chapter 14, Storage Engines. For information about InnoDB differences from standard SQL with regard to treatment of transaction errors, see Section 14.3.13, “InnoDB Error Handling”.

The other nontransactional storage engines in MySQL Server (such as MyISAM) follow a different paradigm for data integrity called “atomic operations.” In transactional terms, MyISAM tables effectively always operate in autocommit = 1 mode. Atomic operations often offer comparable integrity with higher performance. So, MyISAM transactional storage engine always autocommit transaction.

Upvotes: 0

Krystian Lieber
Krystian Lieber

Reputation: 481

If you are using MySQL with MyISAM engine try switching to InnoDB.

For more complicated test you will probably need a mocking framework or DB recreation.

EDIT1: According to the documentation InnoDB is transactional with full ACID support while MyISAM has support for atomic operations. More reading: Transaction and Atomic Operation Differences

EDIT2: In @TransactionConfiguration the default value for defaultRollback is true, so instead of commenting the line you should add @TransactionConfiguration(defaultRollback=false)

Upvotes: 7

user655145
user655145

Reputation:

There's also other solutions for this:

  1. Use a mocking framework (i.e. Mockito) to mock the datasource. This way you will only test your DAO logic
  2. Use a seperate database for testing that can be set up for every test. You can use DBUnit to do this.
  3. Use a in-memory database (i.e. HSQL) so changes won't persist.

This way you won't have to rollback your changes.

Upvotes: 0

Related Questions