Mockito数据源单元测试在Debug模式下执行异常排查
嘿,我之前也碰到过一模一样的坑!这事儿跟Mockito本身没啥关系,锅得甩给IntelliJ的调试器——它偷偷帮你“做了点额外工作”,导致你的预设返回值被提前消耗了。
问题根源
你用Mockito.when(mockResultSet.next()).thenReturn(true, true, false)预设了三次调用的返回值:第一次true,第二次true,第三次false。但调试的时候,IntelliJ的变量视图为了显示ResultSet的内容,会自动调用它的next()方法来遍历结果集——这就相当于提前用掉了一个true!等你代码走到while (rs.next())的时候,剩下的返回值就变成了true, false,自然循环只执行一次就退出了。而正常运行时没有调试器的额外调用,所以预设的返回值序列能正常生效。
解决办法
这里有几个实用的方案,你可以按需选:
关闭调试器的自动求值
在IntelliJ的调试界面,找到「Variables」面板右上角的设置图标(齿轮),取消勾选「Enable auto expressions」或者「Auto evaluate expressions」选项。这样调试器就不会主动调用对象的方法来生成预览了,你的ResultSet的next()调用次数就完全由代码控制。调试时避免直接查看ResultSet变量
如果你不想关自动求值,那调试的时候别点开mockResultSet的变量详情——一旦点开,调试器就会触发next()调用。可以改成在循环内部加日志或者打印语句,比如在ProjectDao的循环里加一行LOG.debug("当前循环执行,处理数据"),这样不用看ResultSet变量也能知道循环执行了几次。改用更鲁棒的Mock方式(可选)
如果你担心这类调试干扰,也可以用Mockito的Answer来手动控制返回值,比如跟踪调用次数:AtomicInteger callCount = new AtomicInteger(0); Mockito.when(mockResultSet.next()).thenAnswer(invocation -> { int count = callCount.getAndIncrement(); return count < 2; // 前两次返回true,第三次及以后返回false });这种方式不管调试器额外调用几次,只要代码里的调用次数是两次,就能正常触发两次循环(当然如果调试器调用太多,还是会影响,但一般调试时的额外调用不会太频繁)。
验证方法
改完之后,你可以再调试试试:如果关闭了自动求值,断点停在while (rs.next())时,不要碰ResultSet变量,直接按步过(F8),就能看到循环执行两次了。
内容的提问来源于stack exchange,提问作者Franck

