Skip to content

Instantly share code, notes, and snippets.

@dpmedeiros
Last active January 28, 2021 06:26
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dpmedeiros/7f7724fdf13fc5390bb05958448cdcad to your computer and use it in GitHub Desktop.
Save dpmedeiros/7f7724fdf13fc5390bb05958448cdcad to your computer and use it in GitHub Desktop.
Mock main thread handler for use in Android unit tests (requires Mockito and PowerMock)
package com.dpmedeiros.androidtestsupportlibrary;
import android.os.Handler;
import android.os.Looper;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.mockito.Mockito.*;
/**
* Utility methods that unit tests can use to do common android library mocking that might be needed.
*/
public class AndroidMockUtil {
private AndroidMockUtil() {}
/**
* Mocks main thread handler post() and postDelayed() for use in Android unit tests
*
* To use this:
* <ol>
* <li>Call this method in an {@literal @}Before method of your test.</li>
* <li>Place Looper.class in the {@literal @}PrepareForTest annotation before your test class.</li>
* <li>any class under test that needs to call {@code new Handler(Looper.getMainLooper())} should be placed
* in the {@literal @}PrepareForTest annotation as well.</li>
* </ol>
*
* @throws Exception
*/
public static void mockMainThreadHandler() throws Exception {
PowerMockito.mockStatic(Looper.class);
Looper mockMainThreadLooper = mock(Looper.class);
when(Looper.getMainLooper()).thenReturn(mockMainThreadLooper);
Handler mockMainThreadHandler = mock(Handler.class);
Answer<Boolean> handlerPostAnswer = new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
Runnable runnable = invocation.getArgumentAt(0, Runnable.class);
Long delay = 0L;
if (invocation.getArguments().length > 1) {
delay = invocation.getArgumentAt(1, Long.class);
}
if (runnable != null) {
mainThread.schedule(runnable, delay, TimeUnit.MILLISECONDS);
}
return true;
}
};
doAnswer(handlerPostAnswer).when(mockMainThreadHandler).post(any(Runnable.class));
doAnswer(handlerPostAnswer).when(mockMainThreadHandler).postDelayed(any(Runnable.class), anyLong());
PowerMockito.whenNew(Handler.class).withArguments(mockMainThreadLooper).thenReturn(mockMainThreadHandler);
}
private final static ScheduledExecutorService mainThread = Executors.newSingleThreadScheduledExecutor();
}
@vadymhimself
Copy link

how to @PrepareForTest protected class ?

@rafalzawadzki
Copy link

Thanks, it helped me a lot! As a sidenote, with Mockito v. 2.4.0 there is no getArgumentAt(int, class) method but just generic getArgument(int)

@Syjgin
Copy link

Syjgin commented Dec 22, 2017

Cannot execute because of mockito 2 is incompatible with PowerMock, so PowerMockito.mockStatic(Looper.class); aborted with error java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment