How to write Robolectric Unit Test Cases?

In this RoboGuice tutorial, I am going to explain you how to write Unit Test Cases to test your Android code with Robolectric. If you are not aware of What Unit Testing is or What Robolectric is, you can checkout my previous tutorial explaining the same.

Robolectric
How to Write Unit Test Cases?

Before moving on to learning how to write Unit Test Cases for Android, lets see how to write Unit Test Cases in general.

As described in my previous tutorial, Unit Testing is the testing of the individual units of source code. Unit Test Cases focus on testing an individual method (or function) or a piece of code in your application. Each method typically expects one or more inputs and gives an output. So, your test cases should simply supply some values as inputs and match the actual output it gives with the expected result. If it matches, your test case passes else it fails.

Say, for example, you write a simple add() method, which should add any two natural numbers but should throw some exception if some negative integers are provided. So, you have got to test this particular method in two different scenarios. One case where you give two positive numbers and verify the actual output. The other case, where you supply negative integers and check for the exception. So, for each scenario, you write one Unit Test Case. Simple!

Now, lets get into more particulars of writing them. The basic funda of writing them is to test only what happens within that method, not what happens beyond its control. Didnt get me? I will explain. Consider this example.

// Business logic Class
public class CarFactory {

    private Tyre tyre;
    private Logo logo;

    public CarFactory() {
        // initializations
    }

    public void manufacture() {
        tyre.fix();
        logo.fix();
    }

}

// Test Class
public class CarFactoryTest {

    @Test
    public void testCarManufacture() {
        carFactory.manufacture();

        verify(tyre).fix();
        verify(logo).fix();
    }

}

Here, in the case of unit testing manufacture() method, we assert our test case by verifying whether calls to tyre.fix() and logo.fix() have been made using the verify() API. But, we dont care about what happens in the fix() method of Tyre class! It is the duty of the Unit Test Cases of Tyre class to test whether the intended functionality happens in that particular call. So, this way, each and every class is covered by their respective test cases which ensure their respective functionality. With this understanding, let us proceed to learning how to write Test Cases using Robolectric.

How to write Robolectric Test Cases?

One basic thing that you have to remember before writing test cases for Android components is that Robolectric doesnt know about the lifecycle of your Activity or Service or whatever the Android class it is. For Robolectric, your Activity's life cycle methods are just like any other normal Java methods. Neither it keeps track of them nor it initializes your Activity's layout and other stuff. It just mocks and stubs them out! It never calls the real methods and executes them.

This means that you can never expect your onCreate() method of Activity to be called when you create an instance of Activity. Also, you can never expect onStart() or onResume() methods to be called after you call onCreate(). You have to call all of them individually in your test cases and test the code in them.

Now, the question that comes to your mind is, "How would it test my code or how would it help me in testing then?" The answer is as stated above, "Its not your job to test the life cycle of Android's Activity class". You should just test whether your intended code gets executed when the appropriate API is called. Robolectric concentrates just on the same. It just tells you whether your intended action has been performed or not.

Confused? To understand it, consider an example of writing Unit Test Case for starting an Activity.

public class MyActivity extends Activity {

    public void startWifiActivity() {
        Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
        startActivity(intent);
    }

}

@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {

    @Test
    public void testStartingWifiActivity() {
        myActivity.startAnotherActivity();

        Intent intent = shadowOf(myActivity).getNextStartedActivity();
        assertEquals(intent.getAction(), Settings.ACTION_WIFI_SETTINGS);
    }

}

Our intention here is to start the Wifi Settings Activity when the startWifiActivity() method of MyActivity is called. We have to write a test case to test the same.

If you look at the test case, we verified the starting of  Wifi Settings Activity by getting some Intent by calling shadowOf(myActivity).getNextStartedActivity() and asserting on it. This is a Robolectric API which stubs out the actual startActivity() method of your Android's SDK. What it does is, it stores the Intent our code used to start the Wifi Settings Activity with. It returns the same intent when you make the above call in your test class. Now, you assert it by checking if the Intent Action is correct or not. So, if the call to startActivity() is not made in your code, this Intent would be null and your test case fails.

Here, Robolectric's intention is not to start the actual Activity. Thats the job of Android OS but not Robolectric! So, Robolectric simply makes sure that the call to the system API is made properly (similar to verifying the method call of tyre.fix() in the above example). Mind you again, we should test our code, but not Android's code! This is how you write your unit test cases for Android.

So, coming to the semantics of writing them, you can see two new things over there, one is @RunWith(RobolectricTestRunner.class) and the other @Test. Let me explain. The first one tells Robolectric Test framework that we want to use the default test runner for testing. A Test Runner is nothing but the one which sets up the environment and runs each test case in the file. We will learn more about this in the upcoming posts. As of now, just remember to annotate the class with this annotation. Coming to @Test annotation, as the name says, it is a test case to be executed. The Test framework goes through your file and executes all the methods which are annotated with this annotation. So, you should always annotate your test case with this to tell the framework that it is a test case.

I will explain you more about the Robolectric APIs and the ways of testing Android components like Activity, Service, etc... in my next tutorials. Stay tuned.

Please do leave your feed back below. Thank you.

HAPPY CODING...!!!

3 comments:

  1. Hello,
    The Article on Robolelectric Unit Test Cases to test your Android code is very informative. It give detail information about it .Thanks for Sharing the information on Robolelectric unit case. Software Testing Company

    ReplyDelete
  2. The Article on Mobile testing Services Map is awesome nice pie chart description, thanks for sharing the information about it. Really good information to show through this blog. I really appreciate you for all the valuable information that you are providing us through your blog.

    Penetration testing services
    Vulnerability assessment services
    Load Testing Services
    Mobile app testing services

    ReplyDelete