How to Set Up Picasso for Robolectric Test
Running tests on an emulator or device is slow. For Android, Robolectric brings faster and reliable unit tests because it runs on the JVM. With Robolectric, you can test Android components such as Activity
and Fragment
. When you test those components, you need to consider something more because they are not a pure business logic class. For example, it could contain code for image loading using Picasso. Picasso is typically initialized in the Application#onCreate
.
Suppose you want to test MainActivity
like below. RobolectricTestRunner
is specified to use Robolectric.
When you run this, IllegalStateException
happens from Picasso. The interesting thing is that testA
would pass but testB
would fail due to this exception. This is because YourApplication
is reused for each test method. Instead of destroying YourApplication
, lifecycle events(e.g. onCreate
and onDestroy
) are called before and after each test. Picasso doesn’t allow to call setSingletonInstance
twice so it throws an exception.
This only happens with Robolectric and never happens in your real device. To resolve this issue, you can modify YourApplication
to catch that exception and ignore it. Given that this doesn’t happen in the production environment, catching exception sounds not great. The better way is to create an application only for Robolectric. You can specify it in robolectric.properties
. When RobolectricTestRunner
runs, it checks this file and that application is used for testing instead of YourApplication
.
test/resources/robolectric.properties
With a static boolean value, you can prevent a double calling on setSingletonInstance
.
test/io/github/sangsoonam/RobolectricApplication.java
Now, let’s think about another point: network request. To show an image, that request is necessary. However, network request or disk access are not recommended while unit testing mainly for better performance. Mostly, you don’t consider image loading result. In that case, you can avoid the request by mocking Picasso.
test/io/github/sangsoonam/RobolectricApplication.java
Answers.RETURNS_MOCKS
makes you avoid having lots of mocking. Without that, you need to mock every method including nested calls.
Last but not least, actually you do not need to concern on the network request. Internally, Picasso uses Dispatcher
and DispatcherThread
to load an image. DispatcherThread
has a looper to handle requests. Robolectric modifies or extends Android class behavior with Shadows. When you run with Robolectric, a looper doesn’t process any queued actions unless you proceed manually. This is an example for the main looper.
Conclusion
Robolectric enables you to test Android components. If Picasso is used in that component, creating RobolectricApplication
is a nice way to keep your production code clean and avoid IllegalStateException
. With Robolectric, you don’t need to worry about network request even if you use a real Picasso. If you prefer mocking, mock it with Answers.RETURNS_MOCKS
.