【问题标题】:Transactional test method not throwing exceptions when using rollback使用回滚时事务测试方法不抛出异常
【发布时间】:2017-09-04 19:04:27
【问题描述】:

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

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

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());
    }
}

【问题讨论】:

    标签: java spring hibernate junit


    【解决方案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)。对 DAO 进行另一次测试。

    【讨论】:

    • 我担心一个简单的事实:为什么在(理论上)应该失败时测试通过了?谢谢你的解释
    猜你喜欢
    • 2020-09-24
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 2022-07-22
    • 2019-01-21
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    相关资源
    最近更新 更多