我目前正在使用 Spring 开发 REST Web 服务,使用 Hibernate 作为 ORM 并使用 cucumber 编写验收测试。
为了能够在场景之间回滚事务,我有以下代码,它在每个场景之前创建一个事务并在其之后回滚。
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);
}
}
在步骤定义类中,我使用实体的 Autowiring CrudRepository 来创建 Give 语句中的内容并断言 then 语句中的内容。
我使用 MockMvc 来模拟应用程序上下文,并使用 (post、get...) 发送虚假请求并将 ResultActions 保留为字段以在断言中使用它。
直到最近,这对我来说都很好,当使用 @Column(unique=true) 来防止实体中的字段之一重复,并使用 DataIntegrityViolationException 来知道我何时要删除该实体时,问题就开始了保存有重复的字段
try{
newUser = userRespoitory.save(newUser);
}
catch(DataIntegrityViolationException exception){
throw new UserNameAlreadyExistsException();
}
问题是,抛出 DataIntegrityViolationException 后,每当我在任何 cucumber 步骤定义函数中使用 UserRepository.findOne() 时,测试都会引发错误
org.hibernate.AssertionFailure: null id in com.komalo.domain.User entry (don't flush the Session after an exception occurs)
我明白这是因为我在每个场景之前创建的事务,如果我在使用 UserRepository 之前回滚该事务,它就会正常工作。
所以我的问题是:
1) 这是编写测试的正确方法吗? ,因为我使用的是 UserRepository,这是我正在进行验收测试的一部分,但我认为由于它是由 Spring Data 实现的,所以应该没问题。
2) 即使在抛出异常之后,是否有办法继续使用事务?
3)这可以通过不依赖 DataIntegrityViolationException 轻松解决,而是通过在接口(interface)中创建一个额外的方法(如 UserRepository.findOneByUsername() )并使用它来手动检查,但这不是正在执行的额外 select 语句吗? ?
最佳答案
好吧,我没有明确的答案,但您最好清理并重新插入数据,或者在代码中添加一些逻辑,例如:
if(userRepositry.findOne(newUser.getName())==null)
newUser = userRespoitory.save(newUser);
但我认为这不是使用 BDD 的正确方法。
您需要将数据创建与存储库和生产代码状态分开,而且您的测试必须彼此独立,因此 clean->run
对我来说看起来不错。
关于java - 在 cucumber-jvm 测试中回滚事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26077921/