amodkanthe
amodkanthe

Reputation: 4530

Android test cases robolectric Shadowlooper idle VS idleFor

using robolectric version 4.5.1

What is the difference between

 shadowOf(getMainLooper()).idleFor(1, TimeUnit.MILLISECONDS);

and

 shadowOf(getMainLooper()).idle();

shadowOf(getMainLooper()).idle(); is causing my test case to fail giving following exception message

Main looper has queued unexecuted runnables. This might be the cause of the test 
failure. You might need a shadowOf(getMainLooper()).idle() call.
java.lang.Exception: Main looper has queued unexecuted runnables. This might be the cause of the test failure. You might need a shadowOf(getMainLooper()).idle() call.
at org.robolectric.android.internal.AndroidTestEnvironment.checkStateAfterTestFailure(AndroidTestEnvironment.java:502)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:581)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:278)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)

But shadowOf(getMainLooper()).idleFor(1, TimeUnit.MILLISECONDS); this works fine how?

as documentation idleFor Advances the system clock by the given time, then executes all posted tasks scheduled before or at the given time. What it means Advances the system clock? How my test is getting passed on using idleFor() instead of idle()

Upvotes: 0

Views: 2826

Answers (1)

primus
primus

Reputation: 50

We can find both functions in ShadowPausedLooper:

  @Override
  public void idle() {
    executeOnLooper(new IdlingRunnable());
  }

  @Override
  public void idleFor(long time, TimeUnit timeUnit) {
    long endingTimeMs = SystemClock.uptimeMillis() + timeUnit.toMillis(time);
    long nextScheduledTimeMs = getNextScheduledTaskTime().toMillis();
    while (nextScheduledTimeMs != 0 && nextScheduledTimeMs <= endingTimeMs) {
      SystemClock.setCurrentTimeMillis(nextScheduledTimeMs);
      idle();
      nextScheduledTimeMs = getNextScheduledTaskTime().toMillis();
    }
    SystemClock.setCurrentTimeMillis(endingTimeMs);
    // the last SystemClock update might have added new tasks to the main looper via Choreographer
    // so idle once more.
    idle();
  }

idle() will only run immediate Runnables where idleFor() will check for next scheduled task and if it exists move system time SystemClock.setCurrentTimeMillis(nextScheduledTimeMs);

We can check ShadowPausedMessageQueue for getNextScheduledTaskTime()

  Duration getNextScheduledTaskTime() {
    Message next = peekNextExecutableMessage();

    if (next == null) {
      return Duration.ZERO;
    }
    return Duration.ofMillis(convertWhenToScheduledTime(shadowOfMsg(next).getWhen()));
  }

Upvotes: 0

Related Questions