Spring集成测试事务未回滚

发布于 2024-11-06 13:04:01 字数 2227 浏览 0 评论 0原文

为基于 Spring 的应用程序编写集成测试遇到事务回滚问题 - 数据已插入,但事务回滚后,数据仍在数据库表中...... Spring 3.0.5,JUnit 4.8.2

集成测试代码

@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());
  }
}

在日志中的调试模式下,我可以看到事务已启动并回滚

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]]]

也许有人知道为什么会发生这种情况?谢谢你的帮助。

更新: 该集成测试生成一些参数,然后使用会话对象的 Mockito 模拟插入到策略服务中。这个模拟对象只是抛出异常,并且在该异常中策略服务数据通过 DAO 层保存到数据库。然后测试通过 DAO 层向数据库发出请求并断言保存的值。

数据是通过Hibernate保存的,所以基本上在我的DAO对象中,对象是以这种方式保存的:

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

sessionFactory是AnnotationSessionFactoryBean,其中数据源是c3p0 ComboPooledDataSource类

更新2:问题出在Mysql引擎上,默认情况下它是MyISAM,所以我只需要把它切换到InnoDB现在一切正常了。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心房的律动 2024-11-13 13:04:01

通常的问题是您的服务层调用其他也标记为 @Transactional 的层,甚至可能使用 REQUIRES_NEW 标记。在这种情况下,测试侦听器只能访问外部事务,但无法回滚内部事务。

通常的问题是 DAO 层上有 @Transactional 注释。如果有,请将其删除。 DAO 层不应该有事务划分。

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.

深空失忆 2024-11-13 13:04:01

尝试从类级别删除 @Transactional 注释,并将其仅用于特定的测试方法。

希望有帮助。

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

Hope it helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文