事务测试方法在使用回滚时不抛出异常

时间:2017-09-04 19:04:27

标签: java spring hibernate junit

测试方法remove正在尝试删除标识为147的某些用户,但此ID不存在。如果我启用Rollback(false)我会得到一个异常(预期的行为)但没有它,测试通过没有问题。所以我有两个问题:

  1. 为什么测试仅在禁用回滚时失败?
  2. 是否有可能 获得启用回滚的异常?
  3. UserDao继承自通用DAO类,它在类级别具有@Transactional(默认选项)和@Repository(带有bean名称)注释。

    Here是我在禁用回滚时获得的异常。

    我正在使用Spring Framework 4.3.9,Hibernate 5.2.10和JUnit 4.12

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @Transactional
    @ContextConfiguration({
            "classpath:myapp-config-test.xml",
            "classpath:hib-test.xml"})
    public class UserControllerTest {
    
        private MockMvc mockMvc;
        private MvcResult mvcResult;
        private final String basePath = "/users/";
    
        @Autowired
        private UserDao userDao;
    
        @Before
        public void setUp() throws Exception {
            mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userDao)).build();
        }
    
        @Test
        //@Rollback(false)
        public void remove() throws Exception {
            mockMvc.perform(delete(basePath + "147")).andExpect(status().isOk());
        }
    }
    

1 个答案:

答案 0 :(得分:2)

从下到上阅读堆栈跟踪:

Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67)
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46)
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3315)
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3552)
    at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:99)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:589)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1435)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2411)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)
    at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:582)
    ... 24 more

您可以看到事务管理器提交事务时发生异常:

at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:582)

提交事务会导致Hibernate会话刷新已经发生的更改并保存在内存中:

at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201)

实际上,flush会导致删除实际上在数据库上执行:

at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:99)

由于删除不删除任何内容,因此抛出异常:

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

因此,为了实际执行删除并抛出预期的异常,您需要刷新。

但是你不应该在MVC控制器的单元测试中测试DAO的行为(甚至更少,Hibernate的行为,已经由Hibernate本身测试过)。相反,您应该在对控制器进行单元测试时模拟控制器(即DAO)的依赖关系。并对DAO进行了另一次测试。