2014-09-27 94 views
2

我目前正在使用Spring开发REST Web服务,使用Hibernate作为ORM并使用黄瓜来编写验收测试。在cucumber-jvm测试中回滚事务

为了能够在场景之间回滚事务,我有以下代码,它在每个场景之前创建一个事务并在其之后进行回滚。

package com.orange.cainet.cucumber; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.web.WebAppConfiguration; 
import org.springframework.transaction.PlatformTransactionManager; 
import org.springframework.transaction.TransactionStatus; 
import org.springframework.transaction.support.DefaultTransactionDefinition; 
import cucumber.api.java.After; 
import cucumber.api.java.Before; 

@WebAppConfiguration 
@ContextConfiguration("classpath:applicationContext.xml") 
public class RollbackTransactionsBetweenScenarios { 

    @Autowired 
    PlatformTransactionManager transactionManager; 

    TransactionStatus transaction; 

    @Before 
    public void beforeScenario(){  
     transaction = transactionManager.getTransaction(new DefaultTransactionDefinition()); 
    } 

    @After 
    public void afterScenario(){ 
     transactionManager.rollback(transaction); 
    } 
} 

在步骤定义类,我用我的实体的自动装配Autowired CrudRepository创造什么样的是在给定的陈述和主张是什么在当时的声明。

我使用MockMvc模拟应用程序上下文并使用(post,get,...)发送假请求并将ResultActions保留为字段以在断言中使用它。

直到最近,这对我来说还是很好的,使用@Column(unique = true)来防止实体中某个字段的重复,并使用DataIntegrityViolationException来知道我是在什么时间以保存具有成对的场

try{ 
    newUser = userRespoitory.save(newUser);   
} 
catch(DataIntegrityViolationException exception){ 
    throw new UserNameAlreadyExistsException(); 
} 

的问题是,DataIntegrityViolationException被抛出后,每当我在任何黄瓜步骤定义函数使用UserRepository.findOne(),测试引发错误

org.hibernate.AssertionFailure: null id in com.komalo.domain.User entry (don't flush the Session after an exception occurs) 

我知道这是因为我在每个场景之前创建的事务,如果在使用UserRepository之前执行了此事务的回滚,它将正常工作。

所以我的问题是:

1)这是写测试,以正确的方式? ,因为我正在使用UserReposistory,这是我进行验收测试的一部分,但我认为它是由Spring Data实现的,因此它可以。

2)是否有办法继续使用事务,即使抛出异常之后?

3)这可以容易地通过不依赖于DataIntegrityViolationException和代替手动检查通过创建在像UserRepository.findOneByUsername(接口的额外方法),并用它来解决,但不是这一个额外的选择语句被执行??

+1

我建议你,而不是回滚你的交易,你可以准备SQL脚本和清理数据库并重新填充每一个交互。这将确保您的数据在每次测试之前处于可信状态。 – Desorder 2014-10-07 03:13:12

回答

1

嗯,我没有一个明确的答案,但你可以更好地清洁并重新插入数据,而不是,或添加一些逻辑代码,如:

if(userRepositry.findOne(newUser.getName())==null) 
newUser = userRespoitory.save(newUser);   

,但我不认为这是一个正确的方式来使用BDD。

您需要将数据创建与您的存储库和生产代码状态分开,并且您的测试也必须相互独立,因此clean->run对我来说看起来不错。

0

那么这个特殊的@txn(特定于Java的)标签可以添加到特性或场景(大纲)中......我认为这是正确的方法。

但是......对我来说,它运行时运行特定的场景,场景纲要或甚至整个功能文件。由于某些原因,当我通过使用@RunWith(Cucumber.class)批注的Java测试类运行功能时,它似乎被忽略。

至于你的子问题#2:另一个特殊的标签是@allow-rescue

关闭黄瓜的异常捕获的标记方案(S)。 当正在测试的代码预计会引发和处理异常时使用。