如何使用Mockito测试handler.postDelayed方法?

5

我是单元测试的新手,现在遇到了一些问题需要测试以下方法:

    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结束后,视图是否可点击。

我该如何实现这种测试?

4个回答

13

如果您能模拟Handler实例,那么可以这样做:

Handler mockHandler = mock(Handler.class);
when(mockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(new Answer() {
@Override public Object answer(InvocationOnMock invocation) throws Throwable { invocation.getArgumentAt(0, Runnable.class).run(); return null; }
});

1

我在模拟 final 的 postDelayed 方法时遇到了麻烦,但由于它归结为非 final 的 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());

1
我遇到了同样的问题,但在我的情况下,我确实需要使用实际的Runnable和实际的delay来运行,因此基于 @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;
    });

0

在 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.*

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接