求助:如何编写JUnit用例覆盖Objects.nonNull判断分支?
JUnit无法覆盖Objects.nonNull判断分支的解决方案
问题代码
public List<ClassRoomListAdapterModel> getRoomListItems() { final List<ClassRoomListAdapterModel> classRoomListItemsList = new ArrayList<>(); if (Objects.nonNull(classRoomListItemsList)) { classRoomListItemsList.addAll(classRoomListItemsList); } return classRoomListItemsList; }
问题根源
这段代码中,classRoomListItemsList是方法内部直接实例化的ArrayList,永远不可能为null,因此Objects.nonNull(classRoomListItemsList)的判断永远为true:
- 正常调用方法时,if分支必然执行,不存在无法覆盖的情况;
- 若你想覆盖判断为false的场景(即变量为null的情况),现有代码结构无法实现,因为变量初始化逻辑硬编码在方法内部,无法模拟null值。
另外,代码中classRoomListItemsList.addAll(classRoomListItemsList)存在逻辑问题:将列表自身元素添加到自身,空列表执行后还是空列表,非空列表会导致元素无限重复(甚至内存溢出),这大概率是笔误,应该是添加外部数据源的元素。
技术解决方案
方案1:重构代码,抽离列表初始化逻辑
将列表的来源改为方法参数,这样在测试时可以传入null值,从而覆盖所有分支:
// 重构后代码:通过参数传入外部列表 public List<ClassRoomListAdapterModel> getRoomListItems(List<ClassRoomListAdapterModel> sourceList) { final List<ClassRoomListAdapterModel> classRoomListItemsList = new ArrayList<>(); if (Objects.nonNull(sourceList)) { classRoomListItemsList.addAll(sourceList); } return classRoomListItemsList; }
对应的JUnit测试用例:
import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; class YourClassTest { private final YourClass yourClass = new YourClass(); @Test void getRoomListItems_whenSourceListIsNull_returnsEmptyList() { List<ClassRoomListAdapterModel> result = yourClass.getRoomListItems(null); assertTrue(result.isEmpty()); } @Test void getRoomListItems_whenSourceListIsNotEmpty_returnsCombinedList() { List<ClassRoomListAdapterModel> sourceList = new ArrayList<>(); sourceList.add(new ClassRoomListAdapterModel()); // 假设该类有默认构造 List<ClassRoomListAdapterModel> result = yourClass.getRoomListItems(sourceList); assertEquals(1, result.size()); } }
方案2:使用PowerMock模拟方法内部的实例化(不推荐,仅作应急方案)
如果无法修改原代码,可以使用PowerMock来拦截new ArrayList<>()的调用,返回null值,从而覆盖判断为false的分支:
import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.util.ArrayList; import static org.junit.jupiter.api.Assertions.*; @RunWith(PowerMockRunner.class) @PrepareForTest(YourClass.class) class YourClassTest { @Test void getRoomListItems_whenListIsNull_returnsNull() throws Exception { // 拦截ArrayList的构造,返回null PowerMockito.whenNew(ArrayList.class).withNoArguments().thenReturn(null); YourClass yourClass = new YourClass(); List<ClassRoomListAdapterModel> result = yourClass.getRoomListItems(); assertNull(result); } }
注意:这种方式会破坏代码的封装性,且增加测试复杂度,仅在无法重构原代码时使用。
内容的提问来源于stack exchange,提问作者Vaibhav Yadav
相关产品推荐
相关产品推荐

