Developer

Unit testing Android apps is easy with Robolectric

Robolectric unit tests can verify expected application behavior, saving you the trouble of deploying your Android app to a device or an emulator.

Unit testing offers significant advantages as a development practice and helps ensure higher quality code with fewer defects. Unfortunately, unit testing Android apps can be challenging.

The Android SDK provides an API that makes assumptions about the environment in which it executes. This means that without a device or an emulator, testing is difficult. Building, deploying, and launching the app for every test is slow and impacts developer productivity. Robolectric provides a framework that allows unit test execution without the need for a device or an emulator.

The following example demonstrates a very basic use of Robolectric to implement unit tests for an Android app. Follow along with the step-by-step tutorial, or download (5.51 MB) and import the project in its entirety.

1. Create a new Android project in Eclipse. Target Android 1.6 or higher. Rename the startup activity to Calculator.java and the corresponding layout to activity_calculator.xml. These files will contain the core of the application logic.

2. For the purpose of our example, we will use a very simple layout. In the /res/ layout/activity_calculator.xml file, we create a linear layout. The linear layout first contains two EditTexts that allow the user to input two numbers. The next element is a Button that will perform the addition when clicked. The last element is a TextView that displays the result of the addition operation.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:layout_gravity="left"
    android:gravity="left"
    tools:context=".Calculator" >
    <EditText
        android:id="@+id/firstNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:inputType="number">
        <requestFocus />
    </EditText>
    <EditText
        android:id="@+id/secondNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="number" />
    <Button
        android:id="@+id/addButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add" />
    <TextView
        android:id="@+id/total"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

3. In the /src directory of the project, we create an activity that handles rendering our layout and registering an OnClickListener with the addButton. The OnClickListener calculates the total of the two numbers the user input and renders the total directly below the add Button.

public class Calculator extends Activity {
      private EditText firstNumber, secondNumber;
      private TextView total;
      private Button addButton;
   @Override
   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_calculator);
     firstNumber = (EditText) findViewById(R.id.firstNumber);
     secondNumber = (EditText) findViewById(R.id.secondNumber);
     addButton = (Button) findViewById(R.id.addButton);
     total = (TextView) findViewById(R.id.total);
     addButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
         String firstNumberResult = firstNumber.getText().toString();
         String secondNumberResult = secondNumber.getText().toString();
         Integer totalResult = Integer.parseInt(firstNumberResult) +
           Integer.parseInt(secondNumberResult);
         total.setText("Total = " + Integer.toString(totalResult));
       }
    });
}
}

4. Now that we have our simple Calculator implementation, we can add Robolectric tests to ensure the app functions as expected. The best way to get started is to follow the Quick Start for Eclipse documentation. These steps will guide you through configuring Eclipse to create and run Robolectric tests.

5. Once the project has been configured for creating and running Robolectric tests, the first unit test can be added. The goal of the first test is to ensure that, when the user inputs two numbers and clicks Add, an appropriate result is displayed in the TextView.

@RunWith(RobolectricTestRunner.class)
public class CalculatorTest {
  private Calculator calculator;
  @Test
  public void testClickAddButton_withPositiveValues() {
    calculator = new Calculator();
    calculator.onCreate(new Bundle());
    calculator.getFirstNumber().setText("1");
    calculator.getSecondNumber().setText("2");
    calculator.getAddButton().performClick();
    assertEquals("3", calculator.getTotal().getText().toString());
  }
}

This test requires the addition of the following getter methods in the Calculator class:

public class Calculator extends Activity {
   // ... ...
   public EditText getFirstNumber() {
     return firstNumber;
   }
   public EditText getSecondNumber() {

return secondNumber;

}
   public Button getAddButton() {
return addButton;
     }
   public TextView getTotal() {

return total;

}
}

Notice that the test directly invokes these components as if it were operating within the Android device. The Robolectric testing framework provides "shadow objects" that override certain aspects of the Android SDK. This allows the code under test to execute outside of the Android environment.

6. The goal of the next test is to ensure that the application handles empty inputs gracefully. Note that the naive implementation of the Calculator fails this test with a NumberFormatException. Once this defect is fixed, a regression test now exists that will ensure future changes to the code do not introduce the same issue.

@RunWith(RobolectricTestRunner.class)
public class CalculatorTest {
  // ... ...
  @Test
  public void testClickAddButton_withEmptyValue() {
    calculator = new Calculator();
    calculator.onCreate(new Bundle());
    calculator.getFirstNumber().setText("1");
    calculator.getSecondNumber().setText("");
    calculator.getAddButton().performClick();
    assertEquals("", calculator.getTotal().getText().toString());
   }
}

These tests demonstrate the value of unit testing with Robolectric. Without the overhead of deploying the application to a device or even an emulator, Robolectric tests can verify expected application behavior. This increases development turnaround and helps developers resolve coding issues before they make their way into production code.

The Robolectric User Guide provides the fundamentals for getting started with this powerful testing framework. Even if you find the framework doesn't provide the support for a test you want to write, it's easy to extend the framework.

So if unit testing is on your to-do list, give Robolectric a try. Unit testing your next Android app has never been so easy.

About

Jacob Orshalick is a software consultant, open source developer, speaker, and author. He is the owner of solutionsfit and co-author of the best-selling Seam Framework: Experience the Evolution of Java EE. His software development experience spans the...

Editor's Picks

Free Newsletters, In your Inbox