Robolectric 4.5.1中ShadowLooper的idle与idleFor区别及报错疑问
Robolectric 4.5.1 idle()与idleFor()差异及异常问题解答
两个方法的核心区别
shadowOf(getMainLooper()).idle():仅执行主线程Looper队列中当前已到期的所有Runnable任务,不会修改Robolectric维护的模拟系统时钟,不会处理调度时间晚于当前模拟时间的任务。shadowOf(getMainLooper()).idleFor(1, TimeUnit.MILLISECONDS):分为两步执行:- 先将Robolectric的模拟系统时钟向前推进指定的时长(此处为1毫秒)
- 再执行所有调度时间早于等于推进后新时钟时间的任务,包含原本的延时任务
「Advances the system clock(推进系统时钟)」的具体含义
Robolectric运行安卓本地单元测试时,不会依赖设备的物理时钟,而是自行维护了一个虚拟的模拟时钟,所有安卓侧的延时调度逻辑(比如postDelayed、动画定时、Handler延时任务等)的时间判断都基于这个虚拟时钟。
推进系统时钟就是直接修改这个虚拟时钟的时间值,向前跳转指定的时长,不需要等待真实的物理时间流逝,等价于模拟时间已经过了对应的时长。
调用idle()抛异常、替换为idleFor()测试通过的原因
你遇到的异常是Robolectric在测试结束后的校验逻辑触发的:测试结束时如果主线程Looper还有未执行的Runnable,就会抛出该异常,异常里的idle()调用建议是通用场景提示,不适用于存在延时任务的场景。
出现该问题的核心原因是你的业务代码中存在延时调度的任务:比如业务代码调用了postDelayed(runnable, 1),这个任务的调度时间是当前模拟时钟+1ms,你调用idle()时,模拟时钟没有变动,该任务还未到期,所以不会被idle()处理,测试结束后Looper队列还有剩余任务就会触发异常。
当你替换为idleFor(1, TimeUnit.MILLISECONDS)后,虚拟时钟向前推进了1ms,原本的延时1ms的任务就变为已到期任务,会被执行清空,Looper队列没有剩余未执行任务,自然不会触发异常。
内容的提问来源于stack exchange,提问作者amodkanthe
相关产品推荐
相关产品推荐

