【问题标题】:Spring integration test with manual transaction management带有手动事务管理的 Spring 集成测试
【发布时间】:2015-08-10 08:23:05
【问题描述】:

我已经阅读了很多关于使用 Spring 进行集成测试的帖子和主题,但没有什么是令人满意或有用的。

我们使用带有 Hibernate、Spring Data 和 Oracle 数据库的 Spring 3.2.3。对于测试,我们还使用 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 自己打开一个事务,而后者的断言失败,因为事务尚未提交。如何在执行最后一个断言之前提交事务?

【问题讨论】:

    标签: spring transactions spring-test-dbunit


    【解决方案1】:

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

    你需要

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

    【讨论】:

    • 使用 lambda 更简单:Object returnedValue = this.transactionTemplate.execute(s -&gt; doSomethingAndReturnAnObject(parameter));
    【解决方案2】:

    如文档中所述

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

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

    并且要启动事务,您必须使用注释您的测试方法或类 像这样的@Transactional 注释。

    @Test
    @Transactional
        public void sampleTest()
        {
    

    【讨论】:

    • 感谢您的回复,但这与@Transactional 无关。这是关于手动提交事务并在之后直接断言数据库是预期状态。 @Transactional 不是必需的,因为在每次测试之前都会重置数据库。
    • 好的,您可能需要通过刷新会话来手动处理提交,因为您已经在 dbunit 的全局测试事务中? SessionFactory.getCurrentSession.flush()
    • 或者通过 Transactional(requires_new) 包装方法将保存部分移动到新的 testSave() 方法中,它可能会在离开方法后提交?
    • 目前没有成功。继续谷歌搜索:也许 @PersistenceContext(type=PersistenceContextType.EXTENDED) private EntityManager entityManager;方便吗?
    猜你喜欢
    • 2022-01-24
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    相关资源
    最近更新 更多