Unit Testing Android Activity with Robolectric

Hello there! Am back with another tutorial on the Robolectric concepts. Today, lets learn how to write Unit Test Cases for Activities. To understand the basic concepts of Robolectric and writing Unit Test Cases, please go through my previous tutorials.

Note : Robolectric Jar of version 2.3 is used in this tutorial.

Robolectric Test Cases
Robolectric Test Cases

Something to remember!

One basic thing you have to remember before you pull your socks to write Unit Test Cases for Activities is that Robolectric does not call the Activity's life cycle methods automatically as in the case of real execution (checkout my previous tutorial to know why).

Robolectric stubs out most of the APIs of Activity to facilitate the test cases. So, you have to initialize the Activity in its own way to start off. With this in mind, lets dive into it.

Diving in!

Let us start by writing a simple "Hello World" Activity. Then we will identify the cases to be tested and will implement Unit Test Cases for them

public class HelloWorldActivity extends Activity implements View.OnClickListener {

    private Button mButton;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mButton = (Button) findViewById(R.id.button);
        mTextView = (TextView) findViewById(R.id.text_view);
        mButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
        startActivity(intent);

        mTextView.setText("After click!");
    }

}

As you can see, its a simple, straightforward code. I just have a TextView and a Button. My job is to launch Wifi settings and set the TextView once the button is clicked.

So, how many unit test cases do you think should we write? Well, you might have guessed it, its two. One to test if Wifi Settings gets launched and the other to test if the TextView's text really got set.

Here are the test cases!

@RunWith(RobolectricTestRunner.class)
public class HelloWorldActivityTest {

    private Activity mActivity;
    private Button mButton;
    private TextView mTextView;

    @Before
    public void setup() {
        mActivity = Robolectric.buildActivity(
                        HelloWorldActivity.class).create().get();
        mButton = (Button) mActivity.findViewById(R.id.button);
        mTextView = (TextView) mActivity.findViewById(R.id.text_view);
    }

    @Test
    public void testForTextViewTextToBeChangedAfterClick() {
        mButton.performClick();

        String text = mTextView.getText().toString();
        assertThat(text, equalTo("After click!"));
    }

    @Test
    public void testForWifiSettingsLaunchAfterClick() {
        mButton.performClick();

        Intent expectedIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
        Assert.assertEquals(
                    shadowOf(mActivity).getNextStartedActivity(),
                    expectedIntent);
    }

}

Initializations

We have seen about @RunWith and @Test annotations in the previous tutorial. But what is this @Before? As the name says, the code in this method runs before the actual test method. We use this method to do any initializations required for test cases. As you can see, initialization of Activity is needed for both the test cases. So, we extract that into setup() method. Similarly, there is an @After method available, and as you might have guessed it, it runs after the execution of each test case.

Remember! In Unit Testing, @Before and @After annotated methods are called for each Test case! Dont think that they are called only once for the entire class. This is because, in Unit Testing, we test each unit as an independent entity. So, we isolate it from the other test cases.

Awesome, now lets get into initializations part in setup() method. As said in the above section, you have to initialize RoboActivity in the Robolectric's way to test. For this, you have to use Robolectric.buildActivity(YourActivity.class) to create a test instance of the Activity. Now, you can call create() on that which calls the onCreate() method and resume() which calls your onResume() method and so on... This way, we can drive through the life cycle methods of the Activity.

Apart from initializing the Activity instance, you get the TextView and Button views similar to how you do in the actual Android Activity.

Testing our code

The first unit test case - This test case is pretty much self-explanatory. You mimic the button click and then check whether the text in Text View is set or not.

The second unit test case - As we learnt in previous tutorials, we should only test if we request system with the desired Intent or not. So, the API getNextStartedActivity() will return the intent with which we called startActivity(). We assert this based on our desired Intent. (Lets learn about shadowOf(Activity) in upcoming tutorials)

Thats it! We wrote our first unit test cases for Activity!

If you use RoboGuice for your Activity, there will be slight modifications to the above code. Don't worry, we'll cover that in the next tutorial.

Please share your views, thoughts or feedback below.

HAPPY CODING...!!!