SpringBoot应用Java 8环境下单元测试使用Optional类返回Items列表时的类型转换异常排查与解决
从错误栈和你的测试代码来看,这个类型转换异常的根源是测试逻辑的错误,具体来说是你误用了Mockito的mock对象,并且错误地mock了被测试类的方法,而不是它的依赖组件。
错误原因分析
错误mock了被测试类的方法:
你在测试里写了when(itemsService.addItemsService(itemListDto)).thenReturn(optionalList);,这完全不符合单元测试的逻辑——我们要测试的就是itemsService.addItemsService方法,不能提前mock它的返回值。这会导致Mockito内部的代理逻辑混乱,进而引发类型转换错误。未正确mock依赖的
ItemRepo的save方法:
错误栈显示异常出现在ItemRepo.save方法,说明你的ItemsService.addItemsService方法内部在调用itemrepo.save(item)时,期望返回Items类型,但Mockito默认会为mock的方法返回null(或者错误的类型,如果之前有错误的mock设置),当代码尝试将返回值转换为Items时,就会抛出ClassCastException(这里看起来是意外返回了Optional类型,和你错误创建的optionalList有关)。
修复后的测试代码
下面是修正后的测试用例,我会标注关键修改点:
@ExtendWith(MockitoExtension.class) public class ItemsMicroserviceApplicationServiceTests { @Mock ItemRepo itemrepo; @InjectMocks ItemsService itemsService = new ItemsService(); List<Items> itemList; @Test void testaddItemsService() { // 1. 准备测试数据 itemList = new ArrayList<>(); Items item1 = new Items(1,"oneplus","good smartwatch",5999); Items item2 = new Items(2,"realme","decent buds",3999); itemList.add(item1); itemList.add(item2); ItemListDto itemListDto = new ItemListDto(itemList); // 2. 正确mock依赖的save方法:当调用repo.save时,返回传入的item(模拟保存成功的场景) when(itemrepo.save(any(Items.class))).thenAnswer(invocation -> invocation.getArgument(0)); // 3. 调用被测试的方法 Optional<List<Items>> result = itemsService.addItemsService(itemListDto); // 4. 添加有效的断言,验证结果和行为 assertTrue(result.isPresent()); assertEquals(itemList.size(), result.get().size()); // 验证repo的save方法被调用了两次(对应两个item) verify(itemrepo, times(2)).save(any(Items.class)); } }
关键修改说明
- 移除了错误的
when(itemsService.addItemsService(...)):我们不再mock被测试方法的返回,而是让它真实执行,依赖mock的ItemRepo来完成逻辑。 - 正确mock
ItemRepo.save方法:使用thenAnswer让save方法返回传入的对象(模拟保存成功的场景),这样service里的代码就能得到正确的Items类型返回值,避免类型转换错误。 - 添加了有意义的断言:替换了无用的
assertTrue(true),改为验证返回结果的正确性,以及验证依赖方法的调用次数,确保测试能真正验证业务逻辑。
额外检查点
如果修复后仍然有问题,建议检查ItemsService.addItemsService方法的第45行代码,确认它调用itemrepo.save后的处理逻辑是否正确,比如是否存在错误的类型转换(比如把Items当成Optional<Items>处理,或者反过来)。
内容的提问来源于stack exchange,提问作者SaiNaveen

