首页 > 使spring单元测试全局默认回滚对某一测试方法不生效

使spring单元测试全局默认回滚对某一测试方法不生效

单元测试基类默认为回滚

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/ApplicationContextTest.xml" })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public abstract class AbstractTest {}

FooService中存在一个标注了事务注解的方法

class FooService{
    @Transaction
    public void doSomething(...){
        //...
        insertFoo(foo);
        if(!meetSomeCondition){ //不满足某一条件 抛异常
             throw new RuntimeException("XXX");
        }  
        //...      
    }
}

现有一个FooServiceTest

public class FooServiceTest extends AbstractTest{
    @Autowired
    private FooService service;
    @Test
    public void test_doSomething_failed_because_not_meet_some_condition(){
            try{
                service.doSomething(...);
                fail();
            }catch(Exception e){
                equals("XXX",e.getMessage())
            }
            //校验抛出异常后 是否回滚了
            int count = service.getFooCount(...);
            assert(0,count); //为0 表示回滚了
    }
}

但执行此单元测试 失败

java.lang.AssertionError: expected:<0> but was:<1>

似乎是因为整个单元测试期间使用了同一个事务, 只有在所有测试方法都结束后才会回滚。
有没有好的办法处理这种情况呢? 如能使基类全局的@Transactional对某个测试方法不生效 , 这时犹如正常调用该方法使用的就是目的方法自带的事务了。

尝试了下面的方法 都未成功

尝试一:

 @Test
 @Rollback(false)
 public void test_doSomething_failed_because_not_meet_some_condition(){...}

尝试二:
专门创建一个测试类 仅包含该测试回滚方法

//显式指定不回滚
@TransactionConfiguration(defaultRollback = false)
public class FooServiceRollbackTest extends AbstractTest{
    
    @Test
    public void test_doSomething_failed_because_not_meet_some_condition(){...}
}

上面两种尝试结果一样
仍是测试失败

java.lang.AssertionError: expected:<0> but was:<1>

同时控制台中还多了异常

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:720)

原因是测试方法(test_doSomething_failed_because_not_meet_some_condition)里调用的service方法(service.doSomething)中的@Transactional会复用外部测试方法的事务, 所以直到测试方法结束后才会回滚, 所以在测试方法内部校验回滚肯定失败。

解决方法

@Test
@Transactional(propagation=Propagation.NOT_SUPPORTED) //添加此注解
public void test_doSomething_failed_because_not_meet_some_condition(){...}
org.springframework.transaction.annotation.Propagation.NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists. 

使用Propagation.NOT_SUPPORTED会取消外部事务, 这时只会使用servcie方法自己的事务。

缺点:
测试方法里的数据库操作 如添加一些测试数据 不会回滚 于是会污染数据库

【热门文章】
【热门文章】