You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JUnit中Mock Hibernate的setFirstResult()与setMaxResults()方法

如何Mock Hibernate的setFirstResult()和setMaxResults()来测试分页功能?

我写了一个用Hibernate实现分页的业务方法,但是在写JUnit测试时没法正确Mock setFirstResult() 和 setMaxResults() 方法,导致测试总是返回全量数据,测试用例失败。以下是我的代码:

业务方法

public List<Issuance> getIssuances(int after, int limit) { 
    CriteriaBuilder builder = db.session().getCriteriaBuilder(); 
    CriteriaQuery<Issuance> criteriaQuery = builder.createQuery(Issuance.class); 
    Root<Issuance> txnRoot = criteriaQuery.from(Issuance.class); 
    Path<Long> idPath = txnRoot.get("id"); 
    criteriaQuery.select(txnRoot); 
    criteriaQuery.orderBy(builder.desc(idPath)); 
    return db.session().createQuery(criteriaQuery).setFirstResult(after).setMaxResults(limit).getResultList(); 
}

现有JUnit测试方法

@Test 
public void getIssuances(){ 
    Issuance issuance1 = new Issuance(); 
    issuance1.setId(1l); 
    Issuance issuance2 = new Issuance(); 
    issuance2.setId(2l); 
    Issuance issuance3 = new Issuance(); 
    issuance3.setId(3l); 
    List<Issuance> expectedIssuances = Arrays.asList(issuance1,issuance2,issuance3); 
    CriteriaQuery<Issuance> criteriaQuery = mock(CriteriaQuery.class); 
    CriteriaBuilder criteriaBuilder = mock(CriteriaBuilder.class); 
    when(dbSession.getCriteriaBuilder()).thenReturn(criteriaBuilder); 
    Root<Issuance> txnRoot = mock(Root.class); 
    when(criteriaBuilder.createQuery(eq(Issuance.class))).thenReturn(criteriaQuery); 
    when(criteriaQuery.from(eq(Issuance.class))).thenReturn(txnRoot); 
    Query<Issuance> query = mock(Query.class); 
    when(query.setFirstResult(eq(0))).thenReturn(query); 
    when(query.setMaxResults(eq(1))).thenReturn(query); 
    when(query.getResultList()).thenReturn(expectedIssuances); 
    when(dbSession.createQuery(eq(criteriaQuery))).thenReturn(query); 
    List<Issuance> result = unit.getIssuances(0,1); 
    assertNotEquals(expectedIssuances.size(), result.size());// 测试用例失败,因为两者数量相等
}

问题根源

你的测试失败主要有两个核心原因:

  1. 你Mock的query.getResultList()直接返回了全部3个对象,但业务方法明确调用了setMaxResults(1),测试时应该返回符合分页规则的子集,而非全量数据。
  2. 没有验证setFirstResult()和setMaxResults()是否被正确调用,无法确保分页逻辑实际执行了。

修正后的测试代码

@Test 
public void getIssuances_shouldReturnPaginatedResults(){ 
    // 1. 准备测试数据
    Issuance issuance1 = new Issuance(); 
    issuance1.setId(1l); 
    Issuance issuance2 = new Issuance(); 
    issuance2.setId(2l); 
    Issuance issuance3 = new Issuance(); 
    issuance3.setId(3l); 
    // 对应after=0, limit=1的预期分页结果(业务方法按id倒序,所以取id最大的那条)
    List<Issuance> paginatedExpected = Arrays.asList(issuance3); 

    // 2. Mock所有依赖节点
    CriteriaQuery<Issuance> criteriaQuery = mock(CriteriaQuery.class); 
    CriteriaBuilder criteriaBuilder = mock(CriteriaBuilder.class); 
    when(dbSession.getCriteriaBuilder()).thenReturn(criteriaBuilder); 
    when(criteriaBuilder.createQuery(eq(Issuance.class))).thenReturn(criteriaQuery); 

    Root<Issuance> txnRoot = mock(Root.class); 
    when(criteriaQuery.from(eq(Issuance.class))).thenReturn(txnRoot); 
    // 补充Mock txnRoot.get("id")的调用
    Path<Long> idPath = mock(Path.class);
    when(txnRoot.get("id")).thenReturn(idPath);
    // Mock criteriaQuery.orderBy()这个void方法
    doNothing().when(criteriaQuery).orderBy(any(Order.class));

    Query<Issuance> query = mock(Query.class); 
    // 链式调用的Mock:确保setFirstResult和setMaxResults返回自身,维持调用链
    when(query.setFirstResult(eq(0))).thenReturn(query); 
    when(query.setMaxResults(eq(1))).thenReturn(query); 
    // 返回分页后的结果,而非全量数据
    when(query.getResultList()).thenReturn(paginatedExpected); 
    when(dbSession.createQuery(eq(criteriaQuery))).thenReturn(query); 

    // 3. 执行测试方法
    List<Issuance> result = unit.getIssuances(0,1); 

    // 4. 断言与验证
    assertEquals(paginatedExpected.size(), result.size());
    assertEquals(paginatedExpected.get(0).getId(), result.get(0).getId());
    // 验证分页方法是否被传入正确参数调用
    verify(query).setFirstResult(0);
    verify(query).setMaxResults(1);
}

关键修改说明

  • 返回分页子集:将getResultList()的Mock返回改为对应分页参数的结果,这样断言时结果大小才会符合预期。
  • 补充缺失Mock:业务方法中调用的txnRoot.get("id")和criteriaQuery.orderBy(...)在原测试中未Mock,可能引发空指针异常,需要补充Mock逻辑。
  • 添加调用验证:用verify()确认setFirstResult()和setMaxResults()被传入正确参数调用,确保分页逻辑确实执行,而非直接返回全量数据。
  • 优化测试命名:把测试方法名改为更具描述性的getIssuances_shouldReturnPaginatedResults,让测试意图更清晰。

内容的提问来源于stack exchange,提问作者Shoaib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:34:06