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; } }
问题原因分析
- ArgumentCaptor使用错误:测试代码中误用
argumentPojoHome(捕获器对象)调用getUserId(),正确的做法应该使用捕获到的实体对象actualHomePreferences,这是导致断言失败的直接原因之一。 - Mock对象未正确注入被测服务:如果
this.service内部仍使用真实的DynamoOtherDao实例,而非mockDynamoOtherDao,则Mock配置完全不会生效,辅助方法会返回真实创建的对象(若真实方法存在变量名错误,返回的对象属性可能未正确赋值)。 - Mock参数不匹配:Mock时指定的参数
USER_ID, LIGHTS, KITCHEN, LIVING_ROOM与addUserToAllowList内部调用setHomePreferences时传入的参数不一致,导致Mock返回未触发,返回默认初始化的对象(userId为0)。 - 外部辅助类代码错误:外部类中存在变量名笔误(
heartsListDynamo应为houseListDynamo),真实运行时会导致空指针异常或属性未正确赋值。
解决步骤
- 修正ArgumentCaptor调用:将断言代码中的
argumentPojoHome替换为actualHomePreferences:assertEquals(actualHomePreferences.getUserId().longValue(), USER_ID); assertEquals(actualHomePreferences.getLights(), LIGHTS); assertEquals(actualHomePreferences.getKitchen(), Kitchen.PUBLIC); assertEquals(actualHomePreferences.getLivingRoom(), LIVING_ROOM); - 确认Mock对象注入:确保
mockDynamoOtherDao已通过构造函数、Setter或@InjectMocks正确注入到this.service中,避免被测服务使用真实实例。 - 验证Mock方法调用:添加验证代码确认Mock方法被正确调用:
若验证失败,检查参数是否完全匹配,或依赖注入是否正确。verify(mockDynamoOtherDao, times(1)).setHomePreferences(USER_ID, LIGHTS, KITCHEN, LIVING_ROOM); - 修复外部类代码错误:修正外部类中的变量名笔误,确保
setHouseListPreferences能正确创建并返回属性赋值完整的对象。
内容的提问来源于stack exchange,提问作者aisy
相关产品推荐
相关产品推荐

