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

Java调用外部类辅助方法时如何正确Mock对象?单元测试报错排查

单元测试断言失败问题排查(Java+Mockito+TestNG)

问题现象

执行断言代码assertEquals(actualListsPreferences.getUserId().longValue(), USER_ID);时触发TestNG断言错误:

[testng] java.lang.AssertionError: expected [999999999999] but found [0]

背景:.setHomePreferences()是被测类this.service外部的辅助方法,归属DynamoOtherDao类。若将该方法移至被测类内部,代码无需Mock即可正常运行;但放在外部类后,即使配置了Mock逻辑,ArgumentCaptor捕获到的对象userId始终为0,Mock未生效。

相关代码

测试代码

ArgumentCaptor<Home> argumentPojoHome = ArgumentCaptor.forClass(Home.class);
ArgumentCaptor<Apt> argumentPojoApt = ArgumentCaptor.forClass(Apt.class);
ArgumentCaptor<DynamoDBTransactionWriteExpression> argumentWriteExp = ArgumentCaptor.forClass(DynamoDBTransactionWriteExpression.class);

doReturn(mockHome)
   .when(mockDynamoOtherDao)
    .setHomePreferences(USER_ID, LIGHTS, KITCHEN, LIVING_ROOM);

this.service.addUserToAllowList(USER_ID, ROLE, CAN_SHARE, USER_ID, LIGHTS, KITCHEN, LIVING_ROOM);

verify(this.mockTransactionWriteRequest, times(2)).addPut(argumentPojoHome.capture(), Matchers.isA(DynamoDBTransactionWriteExpression.class));
verify(this.mockTransactionWriteRequest, times(2)).addPut(argumentPojoApt.capture(), Matchers.isA(DynamoDBTransactionWriteExpression.class));

Home actualHomePreferences = argumentPojoHome.getAllValues().get(0);
Apt actualAptPreferences = argumentPojoApt.getAllValues().get(1);

// 注意:此处存在代码错误,误用ArgumentCaptor对象而非捕获到的实体
assertEquals(argumentPojoHome.getUserId().longValue(), USER_ID);
assertEquals(argumentPojoHome.getLights(), LIGHTS);
assertEquals(argumentPojoHome.getKitchen(), Kitchen.PUBLIC);
assertEquals(argumentPojoHome.getLivingRoom(), LIVING_ROOM);

// 验证事务写请求
verify(this.mockDynamoDBMapper).transactionWrite(mockTransactionWriteRequest);

尝试的Mock逻辑(无效果):

doReturn(mockSharedHeartsListDynamo)
    .when(mockDynamoHeartsListDao)
    .setHeartListPreferences(USER_ID, INFLUENCER_ID, PUBLIC_STATUS, PEN_NAME);

外部辅助类代码

public class DynamoHouseListDao {
    public HouseListDynamo setHouseListPreferences(long userAccountId, String lights, String Kitchen, String LivingRoom) {
        ZonedDateTime now = ZonedDateTime.now(DateTypeConverter.zoneOffset);
        HouseListDynamo houseListDynamo = new HouseListDynamo.Builder(userAccountId,null).build();
        // 注意:此处变量名错误,应为houseListDynamo而非heartsListDynamo
        heartsListDynamo.setKitchen9("");
        heartsListDynamo.set...
        return heartsListDynamo;
    }
}

问题原因分析

  1. ArgumentCaptor使用错误:测试代码中误用argumentPojoHome(捕获器对象)调用getUserId(),正确的做法应该使用捕获到的实体对象actualHomePreferences,这是导致断言失败的直接原因之一。
  2. Mock对象未正确注入被测服务:如果this.service内部仍使用真实的DynamoOtherDao实例,而非mockDynamoOtherDao,则Mock配置完全不会生效,辅助方法会返回真实创建的对象(若真实方法存在变量名错误,返回的对象属性可能未正确赋值)。
  3. Mock参数不匹配:Mock时指定的参数USER_ID, LIGHTS, KITCHEN, LIVING_ROOM与addUserToAllowList内部调用setHomePreferences时传入的参数不一致,导致Mock返回未触发,返回默认初始化的对象(userId为0)。
  4. 外部辅助类代码错误:外部类中存在变量名笔误(heartsListDynamo应为houseListDynamo),真实运行时会导致空指针异常或属性未正确赋值。

解决步骤

  1. 修正ArgumentCaptor调用:将断言代码中的argumentPojoHome替换为actualHomePreferences:
    assertEquals(actualHomePreferences.getUserId().longValue(), USER_ID);
    assertEquals(actualHomePreferences.getLights(), LIGHTS);
    assertEquals(actualHomePreferences.getKitchen(), Kitchen.PUBLIC);
    assertEquals(actualHomePreferences.getLivingRoom(), LIVING_ROOM);
    
  2. 确认Mock对象注入:确保mockDynamoOtherDao已通过构造函数、Setter或@InjectMocks正确注入到this.service中,避免被测服务使用真实实例。
  3. 验证Mock方法调用:添加验证代码确认Mock方法被正确调用:
    verify(mockDynamoOtherDao, times(1)).setHomePreferences(USER_ID, LIGHTS, KITCHEN, LIVING_ROOM);
    
    若验证失败,检查参数是否完全匹配,或依赖注入是否正确。
  4. 修复外部类代码错误:修正外部类中的变量名笔误,确保setHouseListPreferences能正确创建并返回属性赋值完整的对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:06:10