4
votes

Writing integration test for spring based application got problem with transaction rollback - data is inserted, but after transaction rolled back, data are still in database table... Spring 3.0.5, JUnit 4.8.2

Integration Test code

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext.xml" })
@TransactionConfiguration(transactionManager="txManager",defaultRollback=true)
@Transactional
public class GenerateCodeStrategyTest {

  @Autowired
  @Qualifier(value = "generateCodeStrategy")
  private Strategy generateCodeStrategy;

  @Test
  @Transactional
  public void genCodeIntegrationTestCommunicationFailure() {
  //generate some parameters
  SMPPSession mockedSession = mock(SMPPSession.class);
  generateCodeStrategy.setSession(mockedSession);
  generateCodeStrategy.sendRequest(params);
  final SubscribeInfo subscribeInfo = subscribeDao.getUserByPhone(phone);
  assertNotNull(subscribeInfo);
  assertEquals(phone, subscribeInfo.getPhone());
  assertEquals(Status.BAD_STATUS, subscribeInfo.getStatus());
  }
}

In DEBUG mode in logs I can see transaction started and rolled back

INFO: Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@1edd9b3]; rollback [true]
[main] DEBUG org.hibernate.SQL - insert into sms_subscribe (phone_cell, status, ts_subscribe, subscription_status, ts_unsubscribe, receiverIdentification, user_id) values (?, ?, ?, ?, ?, ?, ?) 
INFO: Rolled back transaction after test execution for test context [[TestContext@1f18cbe testClass = GenerateCodeStrategyTest, locations = array<String>['classpath:/applicationContext.xml'], testInstance = lv.mrb.server.service.GenerateCodeStrategyTest@14f1726, testMethod = genCodeIntegrationTestCommunicationFailure@GenerateCodeStrategyTest, testException = [null]]]

Maybe someone have idea why this happens ? Thank you for help.

UPDATED: This integration test generate some parameters, then using Mockito mock of the session object is inserted into Strategy service. This mock object is just throwing exception and on this exception in that Strategy service data is saved to database via DAO layer. Then test make request to database via DAO layer and assert saved values.

Data is persisted via Hibernate so basically in my DAO object object is saved that way

final Session currentSession = sessionFactory.getCurrentSession();
currentSession.save(object);

sessionFactory is AnnotationSessionFactoryBean where datasource is c3p0 ComboPooledDataSource class

UPDATE 2 : The problem was with Mysql engine, by default it was MyISAM, so I just needed to switch it to InnoDB and now all works.

2
could you maybe provide the definition of your tests?Matej Tymes

2 Answers

5
votes

The usual problem is that your service layer calls other layers which are also marked as @Transactional, perhaps even with REQUIRES_NEW. In that case, the Test listener only has access to the outer transaction, but has no way to roll back the inner transaction.

Often the problem is that there are @Transactional annotations on the DAO layer. If there are, remove them. There should be no transaction demarcation on the DAO layer.

0
votes

Try to remove @Transactional annotation from class level and left it only for specific test methods.

Hope it helps.