有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用回滚时不引发异常的java事务测试方法

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

  1. 为什么只有禁用回滚时测试才会失败
  2. 有可能吗 是否获取启用回滚的异常

UserDao继承自一个泛型DAO类,该类在类级别具有@Transactional(默认选项)和@Repository(具有bean名称)注释

Here是禁用回滚时出现的异常

我使用的是SpringFramework 4.3.9、Hibernate5.2.10和JUnit4.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) 个答案

  1. # 1 楼答案

    从下到上读取堆栈跟踪:

    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)
    

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

    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)的依赖关系。再做一次刀的测试