Unit Testing Android Applications With Robolectric

Running unit tests on an Android emulator or device is slow! Building, deploying, and launching the application in an emulator often takes several minutes, and that’s painful. It’s downright unacceptable if you’re planning on running your unit-tests as part of a continuous-integration build process, because the build server will need to launch an emulator every time you build and test.

To make matters worse, Google prevents you from using the Android SDK if it’s not running on a device or emulator. If you do, you’ll be thwarted by a RuntimeException and message:

java.lang.RuntimeException: Stub!

Pivotal Labs’ Robolectric is a unit test framework that de-couples the Android SDK jar so you can test-drive the development of your Android app. Tests run inside the JVM on your workstation in seconds.

With Robolectric, you can write tests like this:

// Test class for MyActivity
@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {
    private Activity activity;
    private Button pressMeButton;
    private TextView results;

    @Before
    public void setUp() throws Exception {
        activity = new MyActivity();
        activity.onCreate(null);
        pressMeButton = (Button) activity.findViewById(R.id.press_me_button);
        results = (TextView) activity.findViewById(R.id.results_text_view);
    }

    @Test
    public void shouldUpdateResultsWhenButtonIsClicked() throws Exception {
        pressMeButton.performClick();
        String resultsText = results.getText().toString();
        assertThat(resultsText, equalTo("Robolectric Rules."));
    }
}

Robolectric makes this possible by intercepting the loading of the Android classes and rewriting the method bodies. Robolectric re-defines Android methods so they return null (or 0, false, etc.), or if provided Robolectric will forward method calls to shadow Android objects giving the Android SDK behavior. Robolectric provides a large number of shadow objects covering much of what a typical application would need to test-drive the business logic and functionality of your application. Coverage of the SDK is improving every day.

Resource Support

Robolectric handles inflation of views, string resource lookups, etc. Some view attributes (id, visibility enabled, text, checked, and src) are parsed and applied to inflated views. Activity and View #findViewById() methods return Android view objects. Support exists for include and merge tags. These features allow tests access resources and to assert on view state.

Run Tests Outside of the Emulator

Run your tests on your workstation, or on your Continuous Integration environment. Because tests run on your workstation in a JVM and not in the emulator Android runtime, the dexing, packaging, and installation on the emulator steps are not necessary, allowing you to iterate quickly and refactor your code with confidence.

Here is a link with step-by-step instructions on getting Robolectric set up in Eclipse.

Potential Robolectric Pitfalls

I ran into a few issues using Robolectric at Breezy:

  • Robolectric doesn’t support all Android SDK APIs
  • Running Robolectric in a team environment is difficult without something like Maven. Eclipse doesn’t allow you to set relative directory paths for libraries by default, so if your Robolectric, Android SDK, and JUnit libraries live in different paths on different developer’s machines, you’ll have a tough time sharing a configured test project.
  • Robolectric caches its shadow classes, which can produce unexpected test results. Here’s a blog post about mitigating this.

Despite these few nuances, I love Robolectric. Here’s a great how-to video on Robolectric by Pivotal Labs, and here’s a link to the Robolectric Google Group if you run into problems.


About this entry