29

Jul

2013

Unit Testing Remote Images on Android with Picasso and Robolectric

By: July 29, 2013

Here at AWeber we use several Square Open Source projects in the networking stack for our Android applications including Picasso, Retrofit, and OkHttp. We also use Robolectric for unit testing.

Picasso is an amazing library for downloading, displaying, and caching images on Android. However this type of functionality can be challenging to unit test. Testing an Activity or Fragment that uses Picasso to asynchronously load remote images can lead to network errors, race conditions, and NPEs in a background thread.

According to Michael Feathers, this type of test isn't really a unit test at all, as it violates (at least) two of the rules for unit tests he sets out in Working Effectively with Legacy Code.

Unit tests run fast. If they don't run fast, they aren't unit tests.

Other kinds of tests often masquerade as unit tests. A test is not a unit test if:

1. It talks to a database.
2. It communicates across a network.
3. It touches the file system.
4. You have to do special things to your environment (such as editing configuration files) to run it.

The solution? Subclass and override. Introduce a MockPicasso class in the unit test environment. It replaces the real Picasso singleton instance and overrides its behavior. For example, the MockPicasso class:

  • Prevents actual network requests to download images.
  • Tracks each image path (URL) requested and target ImageView.
  • Provides accessors to sense the paths and views requested.
  • "Executes" each request synchronously (no background threads).

The end result is that you can write a test for displaying a remote image without actually downloading (or caching) the image. Besides, we want to test our application code, not the Picasso framework (which I assure you is already thoroughly tested).

In this example, MyActivity displays an avatar image located at the URL passed via an Intent extra.

MyActivity.java

Rather than loading the actual image over the network, MyActivityTest simply asserts that the correct image path and target view were requested.

MyActivityTest.java

The MockPicasso class is rather simple. It does little more than record the paths and views requested.

MockPicasso.java

Of course in proper test-driven fashion MockPicasso was written with its own set of unit tests to verify the behavior of the mock.

MockPicassoTest.java

If you would like try using MockPicasso just copy the file into your project. The MockPicasso class must live in the com.squareup.picasso package since it needs access to the package private constructor and the singleton variable. Also make sure to call MockPicasso.init() before each test.

Happy testing!

Chuck Greb
@ecgreb

Chuck is a Mobile Platform Architect at AWeber and co-organizer of Android Alliance Philadelphia.

Comments are closed.