【问题标题】:Robolectric: run looper of handler in my caseRobolectric:在我的情况下运行处理程序的循环器
【发布时间】:2016-03-09 07:09:39
【问题描述】:

我有一个非常简单的类,它有一个Handler,当它处理消息时它会再次发送新消息:

public class MyRepeatTask{
  …
  public void startTask() {
    // send message with delay 5 sec
    handler.sendMessageDelayed(handler.obtainMessage(…), 5000);
  }

  Handler  handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // I put a log for unit test
            System.out.println(“handling message …”);
            // send message with delay again
            handler.sendMessageDelayed(handler.obtainMessage(…), 5000);
        }
  }
}

正如您在上面看到的,当startTask() 被调用时,处理程序会在 5 秒后开始发送消息。然后,在handleMessage() 回调中,handler 再次发送一条延迟 5 秒的消息。这样做的目的是重复做一些任务(比如System.out.println())。

我用Robolectric测试上面的类:

@RunWith(RobolectricTestRunner.class)
public class MyRepeatTaskTest {
  @Test
  public void testStartTask() {
    MyRepeatTask task = new MyRepeatTask();
    task.startTask();

    // run looper of ‘handler’ in task
    ShadowLooper shadowLooper = Shadows.shadowOf(task.handler.getLooper());
    shadowLooper.runToEndOfTasks();

    // sleep for 30 seconds
    Thread.sleep(30 * 1000);
  }
}

我希望每 5 秒看到一次 System.out.println() 消息“handling message …”。但是,当我运行测试时,我只能在终端中看到消息 once

看起来 handlerLooper 只运行了 一个 任务,然后就停止了。

如果我是对的,如何让弯针在 Robolectric 中一直运行?如果我错了,为什么我只看到一条日志消息?

========== 更新 ===========

我尝试了@rds 的答案,我将Thread.sleep(30 * 1000); 替换为:

for (int i = 0; i < N; i++){
   shadowLooper.runToEndOfTasks();
}

现在我可以看到 N 次“handling message …”。但是,整个测试并没有模拟延迟。我用handler.sendMessageDelayed(handler.obtainMessage(…), 5000)发送消息时有5秒延迟,是不是Robolectric框架根本不模拟这种延迟消息???我的考试怎么会有延迟?

【问题讨论】:

    标签: java android unit-testing robolectric


    【解决方案1】:

    问题是当你调用runToEndOfTasks();时,在这个阶段只有一个任务。

    您应该调用shadowLooper.runToEndOfTasks(); N 次来让您的处理程序调用 N 次,而不是让测试线程休眠。

    【讨论】:

    • 这也是一个更强大的测试,这也是 Robolectric 如此工作的原因。根据代码执行所需的时间,您不知道在 30 秒内将执行多少次迭代,但测试确切地知道 runToEndOfTasks() 被调用了多少次。
    • 谢谢。你的意思是我应该用一个调用 runToEndOfTasks() N次的for循环来替换线程睡眠吗? for (int i = 0; i &lt; N-1; i++){shadowLooper.runToEndOfTasks();}
    • 是的,我就是这个意思。测试不应该依赖于实时。如果您想测试您的应用是否随时间变化,请使用ShadowSystemClock 或注入一个您可以模拟的时钟。例如,添加循环 shoadowClock.sleep(5000),因为您知道真正的实现在每个后台任务之间休眠 5000 毫秒。
    【解决方案2】:

    我在从 api-webservice 实现计划下载时遇到了类似的问题。除了处理程序之外,我还实现了一个计时器。我每天都用它来完成一项任务(或者在你的情况下几秒钟)。也可以设置次数...

    Timer Reference Android

    【讨论】:

      【解决方案3】:

      您似乎正在寻找ShadowLooper#idle(long)。这将允许您小心地提前处理程序的时间并断言任务是否正在以不同的时间间隔运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-12-10
        • 1970-01-01
        • 1970-01-01
        • 2016-05-16
        • 1970-01-01
        • 2016-10-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多