【问题标题】:JUnit tests always rollback the transactionsJUnit 测试总是回滚事务
【发布时间】: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?

【问题讨论】:

  • 你从哪里得到异常?你可以发布堆栈跟踪吗?

标签: java spring junit4


【解决方案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 回滚。
      • 仅适用于已检查的异常。未选中将自动回滚。 stackoverflow.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】:
          1. 在您的测试类级别添加@Rollback

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-27
            • 1970-01-01
            • 2016-01-11
            • 2023-03-21
            • 2012-01-27
            • 1970-01-01
            相关资源
            最近更新 更多