【问题标题】:how to test handler.postDelayed with mockito?如何用 mockito 测试 handler.postDelayed?
【发布时间】:2017-05-09 09:43:51
【问题描述】:
我是单元测试的新手,我坚持使用以下方法进行测试:
fun freeze(view: View) {
view.isClickable = false
handler.postDelayed({
view.isClickable = true
}, CLICK_TIMEOUT)
}
这是我已经拥有的:
@Test
fun freeze() {
var view = mock<View>()
viewUtil.freeze(view)
assertFalse(view.isClickable)
}
但现在我需要测试该视图在CLICK_TIMEOUT 之后是否可以点击。
如何实施这种测试?
【问题讨论】:
标签:
android
unit-testing
mockito
【解决方案1】:
如果你能够模拟 Handler 实例,你可以这样做:
Handler mockHandler = mock(Handler.class);
when(mockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(new Answer() {
@覆盖
公共对象答案(InvocationOnMock 调用)抛出 Throwable {
invocation.getArgumentAt(0, Runnable.class).run();
返回空值;
}
});
【解决方案2】:
我在模拟最终的postDelayed 方法时遇到了麻烦,但由于它归结为非最终的sendMessageAtTime,所以我改为模拟了它。使用spy 避免模拟其他Handler 方法。
spyHandler = spy(new Handler(getMainLooper()));
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Message message = invocation.getArgument(0);
message.getCallback().run();
return true;
}
}).when(spyHandler).sendMessageAtTime(any(Message.class), anyLong());
【解决方案3】:
我遇到了同样的问题,但在我的情况下,我真的应该用实际的 delay 运行实际的 Runnable,所以基于 @mrtowel 的回答,我最终得到了以下代码:
Handler handler = mock(Handler.class);
when(handler.postDelayed(any(Runnable.class), anyLong())).thenAnswer((Answer) invocation -> {
new Thread(() -> {
try {
Thread.sleep(invocation.getArgument(1));
} catch (InterruptedException e) {
e.printStackTrace();
}
((Runnable) invocation.getArgument(0)).run();
}).start();
return null;
});
【解决方案4】:
在 kotlin 中只需使用下面的
val handler: Handler = mock(Handler::class.java)
Runnable.postDelayed() ->
`when`(handler.postDelayed(any(Runnable::class.java), anyLong())).thenAnswer {
(it.arguments[0] as Runnable).run()
true
}
Runnable.post() ->
`when`(handler.post(any(Runnable::class.java))).thenAnswer {
(it.arguments[0] as? Runnable)?.run()
true
}
进口
import org.mockito.ArgumentMatchers
import org.mockito.Mockito.*