Spring 与手动事务管理的集成测试

Spring integration test with manual transaction management

我已经阅读了很多关于使用 Spring 进行集成测试的帖子和主题,但没有任何内容令人满意或有帮助。

我们将 Spring 3.2.3 与 Hibernate、Spring Data 和 Oracle 数据库一起使用。为了进行测试,我们还使用了 DbUnit 和 Spring-test-dbunit。在生产代码中,事务由控制器启动,服务本身对事务一无所知。

所以,这是我的测试:

@ContextConfiguration // ...
@ActiveProfiles // ...
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    ModifiedDbUnitTestExecutionListener.class })
@DbUnitConfiguration(databaseConnection = "oracleConnection")
@DatabaseSetup("/database/snapshot/snapshot.xml")
public class IntegrationTest extends AbstractTransactionalJUnit4SpringContextTests
{
    @Test
    public void sampleTest()
    {
        // transaction is already started

        this.assertThatNewsContains(0);

        News news1 = new News();
        news1.setTitle("Test News 1");
        News savedNews1 = this.newsService.save(news1);
        Assert.assertTrue(savedNews1.getId() > 0);

        News news2 = new News();
        news2.setTitle("Test News 2");
        News savedNews2 = this.newsService.save(news2);
        Assert.assertTrue(savedNews2.getId() > 0);

        News news3 = new News();
        news3.setTitle("Test News 3");
        News savedNews3 = this.newsService.save(news3);
        Assert.assertTrue(savedNews3.getId() > 0);

        // transaction commit should occur HERE
        // @todo: HOW ?!

        this.assertThatNewsContains(3);
    }

    private void assertThatNewsContains(int newsSize)
    {
        List<News> allNews = this.newsService.getNews();
        Assert.assertEquals(newsSize, allNews.size());
    }

}

我发现,如果我用 @Transactional(propagation=Propagation.REQUIRES_NEW) 注释 NewsService,测试工作正常,但它与生产模式不同。 @Transactional(propagation=Propagation.REQUIRED) 是不够的,因为 DbUnit-Spring-test 自己打开一个事务,而后者断言失败,因为事务尚未提交。如何实现在执行最后一个断言之前提交事务?

如文档中所述

http://springtestdbunit.github.io/spring-test-dbunit/

如果您已使用 DbUnitTestExecutionListener 将 DBUnit 测试配置为 运行,并且还在使用 TransactionalTestExecutionListener,您可能会遇到在数据设置或滚动之前未启动事务的问题在验证预期结果之前返回。为了使用 DBUnit 支持 @Transactional 测试,您应该使用 TransactionDbUnitTestExecutionListener class.

要启动交易,您必须注释您的测试方法或 class @Transactional 注释是这样的。

@Test
@Transactional
    public void sampleTest()
    {

我终于设法在单独的事务中执行了一些代码。

你需要

@Autowired
private PlatformTransactionManager          platformTransactionManager;

private TransactionTemplate             transactionTemplate;

在你的测试中class。然后您可以执行以下操作:

this.transactionTemplate = new TransactionTemplate(this.platformTransactionManager);

// note that parameters passed to the transaction must be final!
final Object parameter = something;

Object returnedValue = this.transactionTemplate.execute(new TransactionCallback<Object>()
    {
        @Override
        public Object doInTransaction(TransactionStatus status)
        {
            return doSomethingAndReturnAnObject(parameter);
        }
    }
);