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

带手动事务管理的Spring集成测试,spring,transactions,spring-test-dbunit,Spring,Transactions,Spring Test Dbunit,我读过很多关于Spring集成测试的帖子和帖子,但没有什么是令人满意的或有用的 我们将Spring3.2.3与Hibernate、Spring数据和Oracle数据库一起使用。对于测试,我们还使用DbUnit和Spring测试DbUnit。在生产代码中,事务由控制器启动,服务本身对事务一无所知 所以,这是我的测试: @ContextConfiguration // ... @ActiveProfiles // ... @RunWith(SpringJUnit4ClassRunner.class)

我读过很多关于Spring集成测试的帖子和帖子,但没有什么是令人满意的或有用的

我们将Spring3.2.3与Hibernate、Spring数据和Oracle数据库一起使用。对于测试,我们还使用DbUnit和Spring测试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());
    }

}
@ContextConfiguration//。。。
@ActiveProfiles/。。。
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
ModifiedBunitteExecutionListener.class})
@DbUnitConfiguration(databaseConnection=“oracleConnection”)
@数据库设置(“/database/snapshot/snapshot.xml”)
公共类IntegrationTest扩展了AbstractTransactionalJUnit4SpringContextTests
{
@试验
公共无效样本测试()
{
//事务已启动
此.assertThatNewsContains(0);
新闻1=新新闻();
新闻1.设置标题(“测试新闻1”);
News savedNews1=this.newsService.save(news1);
Assert.assertTrue(savedNews1.getId()>0);
新闻2=新新闻();
新闻2.设置标题(“测试新闻2”);
News savedNews2=this.newsService.save(news2);
Assert.assertTrue(savedNews2.getId()>0);
新闻3=新新闻();
新闻3.设置标题(“测试新闻3”);
News savedNews3=this.newsService.save(news3);
Assert.assertTrue(savedNews3.getId()>0);
//事务提交应该在这里发生
//@todo:怎么会?!
本.资产说明新闻包含(3);
}
私有void资产thatNewsContains(int newsSize)
{
List allNews=this.newsService.getNews();
Assert.assertEquals(newsize,allNews.size());
}
}

我发现,如果我用
@Transactional(propagation=propagation.REQUIRES_NEW)
注释新闻服务,测试工作正常,但与生产模式不同
@Transactional(propagation=propagation.REQUIRED)
不够,因为DbUnit Spring测试本身打开了一个事务,而后者断言失败,因为该事务尚未提交。如何在执行最后一个断言之前提交事务?

如文档中所述

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

要启动事务,您必须使用 @像这样的事务注释

@Test
@Transactional
    public void sampleTest()
    {

我最终在一个单独的事务中执行了一些代码

你需要

@Autowired
private PlatformTransactionManager          platformTransactionManager;

private TransactionTemplate             transactionTemplate;
在你的测试课上。然后您可以执行以下操作:

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);
        }
    }
);
this.transactionTemplate=新的transactionTemplate(this.platformTransactionManager);
//请注意,传递给事务的参数必须是最终参数!
最终对象参数=某物;
Object returnedValue=this.transactionTemplate.execute(new TransactionCallback())
{
@凌驾
公共对象doInTransaction(TransactionStatus状态)
{
返回dosomething和returnanObject(参数);
}
}
);

感谢您的回复,但这与@Transactional无关。它是关于手动提交事务,然后直接断言数据库是预期状态。@Transactional不是必需的,因为在每次测试之前都会重置数据库。是否需要通过刷新会话来手动处理提交,因为您已经在dbunit的全局测试事务中?SessionFactory.getCurrentSession.flush()或通过事务性(requires_new)包装方法将保存部分移动到新的testSave()方法中,可能会在离开该方法后提交?目前为止未成功。不断搜索:可能是@PersistenceContext(type=PersistenceContextType.EXTENDED)私有EntityManager EntityManager;使用lambdas更简单:
objectreturnedvalue=this.transactionTemplate.execute(s->doSomethingAndReturnAnObject(参数))