JUnit测试总是回滚事务。

35

我正在对一个应用的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?


你在哪里遇到了异常?能否提供堆栈跟踪信息? - nwinkler
8个回答

67

它应该按照你期望的那样工作,但是你的测试类中可能打开了另一个事务或者你的代码中存在其他功能或错误。

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

@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参考手册第9.3.5.4节事务管理(或当前版本


20

只需添加注释“Rollback”并将标志设置为false即可。

   @Test
   @Rollback(false)

1
我在我的测试类顶部使用了@Rollback(false)。谢谢。 - Aakash

9

希望测试能够修改你的数据库并保持修改是很奇怪的。测试应该是正交的:没有一个测试依赖于另一个测试。

此外,测试应该独立于测试顺序,甚至是幂等的idempotent

所以要么你想在setUp()方法中更改你的数据,然后在tearDown()方法中回滚更改,要么你想为测试设置一个具有良好值的测试数据库。

也许我在这里漏掉了什么,但通常情况下你不应该想这样做。


40
但这不是问题的关键。 - Ralph
12
我有一个非常好的理由,为什么不回滚JUnit测试。因此,“正确答案”不是你不应该这样做。正确的答案是能够解释如何做到这一点的人。 - user829237
请问您能否在setUp方法中添加一些注释,以便在测试代码中任何地方都可以看到如何添加数据并回滚吗? - kboom
这非常取决于数据库!@kboom - Snicolas
6
不回答问题。有时您会使用Junit功能来实现各种目的。如果有人问我想在Junit中进行提交,提供如何执行此操作的答案,然后说如果是真正的Junit(可重复测试),这可能不是最佳实践。 - Espresso
1
@SeanPatrickFloyd 提示在于 REQUIRED_NEW,这表明他显然正在执行集成测试之前设置特定的数据库状态。因此,在测试的实际部分之前需要将其持久化。 所以,是的,我认为我们应该坚持回答问题。 - Sheepy

6

对我来说非常困惑的是,即使异常一路上升冒泡,测试也会提交txn,而通常(与测试方法上的@Transactional相反,在业务类上)这将触发txn回滚。 - Juan Bustamante
仅适用于已检查的异常。未经检查的异常将自动回滚。https://dev59.com/vHA65IYBdhLWcg3wqQY8 - harryssuperman

3
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...
      }

0
  1. 在你的测试类级别上添加 @Rollback

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


0

我同意 Ralph 的回答。

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

根据我的简单经验,注释 @Transactional 将适当地工作,以定义每个单独测试应该运行的事务上下文,并将特定的当前回滚条款委托给此上下文(如 Ralph 所示)。

Ralph 的回答很有用,同时 Snicolas 的回答涉及管理测试上下文的特殊情况。 幂等性对于集成和自动化测试至关重要,但应该有不同的实现方式。 问题是,你们有哪些方法?这些方法有什么行为?

   [...]
   @Transactional

   public class Test {

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

   [...]

这是一个简单、问题连贯的方式 :)


0
自动回滚在类级别注解中被禁用。
@Transactional(propagation = NOT_SUPPORTED).

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接