JUnit 测试总是回滚事务

Posted

技术标签:

【中文标题】JUnit 测试总是回滚事务【英文标题】:JUnit tests always rollback the transactions 【发布时间】:2012-03-22 06:21:12 【问题描述】:

我正在对应用程序 DAO 运行一个简单的 JUnit 测试。问题是我总是得到:

javax.persistence.RollbackException: Transaction marked as rollbackOnly

JUnit 测试是:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:com/my/app/context.xml"
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public class PerformanceTest 

    @Test
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    @Rollback(false)
    public void testMsisdnCreationPerformance() 
        // Create a JPA entity

        // Persist JPA entity
    

如您所见,我明确声明不回滚此方法。

Spring JUnit 支持是否总是将回滚设置为 true?

【问题讨论】:

你从哪里得到异常?你可以发布堆栈跟踪吗? 【参考方案1】:

它应该像你期望的那样工作,但可能是你在你的测试类中打开了另一个事务,或者你在某个地方有其他功能/或错误。

顺便说一句,这个注释应该足够了:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:com/my/app/context.xml"
@Transactional
public class PerformanceTest 

    @Test
    @Rollback(false)
    public void testMsisdnCreationPerformance() 
        // Create a JPA entity

        // Persist JPA entity
    

@见Spring Reference Chapter 9.3.5.4 Transaction management

【讨论】:

【参考方案2】:

只需添加注解 Rollback 并将标志设置为 false。

   @Test
   @Rollback(false)

【讨论】:

【参考方案3】:

想要一个更改您的数据库并保留修改的测试是很奇怪的。 测试应该是正交的:没有测试依赖于另一个。 此外,测试应该独立于测试顺序,甚至idempotent。

因此,要么您想在 setUp() 方法中更改数据库并回滚 tearDown() 方法中的更改,要么您想设置一个测试数据库,其中包含一些用于测试的好值。

也许我在这里遗漏了一些东西,但通常你不应该这样。

【讨论】:

但这不是问题。 我有一个很好的理由不回滚 junit 测试。因此,“正确答案”并不是您不应该这样做。正确的答案是可以解释如何的人。 能否请您添加一些关于如何在设置方法中添加一些数据的评论,仍然可以在被测代码中的任何地方看到它然后回滚它? 不回答问题。有时您将 junit 功能用于各种目的。如果有人问我希望能够在 junit 中提交 - 提供如何做到这一点的答案,然后说如果它是真正的 junit(可重复测试),这可能不是最佳实践。 @SeanPatrickFloyd 提示在 REQUIRED_NEW 上,这表明他显然正在尝试在执行集成测试之前设置特定的数据库状态。因此,它需要在测试的行为部分之前持久化。所以是的,我认为我们应该坚持回答这个问题。【参考方案4】:

来自官方文档:

默认情况下,测试事务会自动回滚 完成测试;然而,事务提交和回滚 可以通过@Commit 和@Rollback 以声明方式配置行为 注释

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html#integration-testing-annotations

@Commit 表示该事务为一个事务性测试方法 应在测试方法完成后提交。 @Commit 可以 用作@Rollback(false) 的直接替代品,以便更多 明确传达代码的意图。

【讨论】:

令我非常困惑的是,即使异常一直冒泡,测试也会提交 txn,通常情况下(@Transactional 在业务类上而不是在测试方法上)会触发txn 回滚。 仅适用于已检查的异常。未选中将自动回滚。 ***.com/questions/3701376/…【参考方案5】:
I use Junit5, both commit and rollback(false) works with me.

    @ExtendWith(SpringExtension.class)
    @SpringBootTest
    @Transactional
    public class MyIntegrationTest 

      @Test
      @DisplayName("Spring Boot Will Rollback Data, " +
      "Can Disable it By Add @Commit Or @Rollback(false) Annotation")
      //@Commit
      //@Rollback(false)
      public void test() throws Exception 
       //your test codes here...
      

【讨论】:

【参考方案6】:

我同意拉尔夫的回答。

Propagation.REQUIRES_NEW 创建一个新事务,这可能与运行测试的主要事务路由不匹配。

根据我的简单经验,注释 @Transactional 将正常工作以定义每个测试应在其中运行的事务上下文,将特定的当前回滚子句委托给该上下文(如 Ralph 所示)。

Ralph 的答案很有用,同时 Snicolas 的答案涉及管理测试上下文的特定案例。 幂等性是集成和自动测试的基础,但应该以不同的方式来实现它们。 问题是,你有什么样的方法?这些方法有什么行为?

   [...]
   @Transactional

   public class Test 

   @Test
   @Rollback(false)
   public void test() 

   [...]

是简单的,问题连贯的方式:)

【讨论】:

【参考方案7】:

    在您的测试类级别添加@Rollback

    在您的测试方法中添加@Transactional(value = "your_ManagerName",rollbackFor = Exception.class)

【讨论】:

以上是关于JUnit 测试总是回滚事务的主要内容,如果未能解决你的问题,请参考以下文章

Junit测试在事务后不回滚

事务回滚在 JUnit5 的 @Nested 类的测试用例中不起作用

spring测试事务回滚,抛出RuntimeException

Spring JPA Junit 关闭自动回滚

使用 Jooq 进行集成测试

MyBatis和SpringMVC集成事务在Junit测试下有效但是在实际项目无效的问题