Robolectric : Unit Test Your Android Application.

“If you don’t care about quality, you can meet any other requirement.” – Gerald M. Weinberg

Need Of Android Application Testing :
The word “Testing” is a large umbrella, and is usually better understood when you break it down to specific types of testing. Here our focus will be on Android application unit testing.
We all know the testing is essential to verify the behaviour of the software or application you write. It ensures that the application is working as expected without any crashes and errors. Especially in Android world with its huge variety of devices and OS versions, testing becomes more critical.

Need Of Test Driven Development :
TDD means letting your test drive your development process.

Basically the process is :
Write a test : write a test case to test the small functionality that you want.
Write a small snippet of code : add more detailed functionality to check the test.
Repeat : go back to step 1 until you have written all the test cases for the functionality you want to test.

TDD takes the testing of the application to the next level and improves productivity by :
1. Minimising time spent on debugging.
2. Reducing the need of manual checking by developers and testers.
3. Helping developers to maintain focus.

Robolectric

Robolectric is a popular unit test framework for android applications, it takes a different and very interesting approach by allowing you to run your Android unit tests in the normal JVM (Java Virtual Machine), without the need of an emulator. This enables your tests to run within your IDE. It is based on the the JUnit 4 framework and supports resource handling, e.g. inflation of views.

How Robolectric works :
Robolectric defines many shadow classes, which modify or extend the behaviour of classes in the Android OS. When an Android class is instantiated, Robolectric looks for a corresponding shadow class, and if it finds one, it creates a shadow object to associate with it. Every time a method is invoked on an Android class, Robolectric ensures that the shadow class’ corresponding method is invoked first, so it has a chance to work its magic.

Setting the project for Robolectric :
There are few steps that you have to follow before start writing the test cases in Robolectric. Please refer the link for setting up the environment.

Robolectric basic test case format:

package com.test.activities;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

@RunWith(RobolectricTestRunner.class)
public class SampleTestCase {
/**
 The @Before methods will be run before every test case,
 so will probably be run multiple times during a test run.
 @throws Exception.
*/
    @Before
    public void setUp() throws Exception {
        // code.
    }

/**
 The @Test annotation identifies a method as a test method.
*/
    @Test
    public void test() {
        fail("Not yet implemented");
    }

/**
 The @After methods will be run after every test case, 
 so will probably be run multiple times during a test run.
 @throws Exception.
*/
    @After
    public void tearDown() throws Exception {
        // code.
    }
}

Following are the possible test cases using Robolectric:

1) To test the content view of the activity.

@Test
public void testLayoutOnCreate() {
    assertEquals(R.id.test_layout_root, shadowOf(testActivity).getContentView().getId());
}

2) To test the visibility of the layout/view.

@Test
public void testViewVisibility() throws NullPointerException {
    /**
    * here view.getVisibility() returns
    * 0 - VISIBLE
    * 4 - INVISIBLE
    * 8 - GONE
    */
    String visibility = null;
    switch(your_relativeLayout.getVisibility()) {
        case 0 :
            visibility = "VISIBLE";
        break;

        case 4:
            visibility = "INVISIBLE";
        break;

        case 8:
            visibility = "GONE";
        break;
    }
    System.out.println("The visibility of View "+visibility);
    assertTrue(true);
}

3) To test text from res/values/strings.xml

@Test
public void testTextFromStrings_xml() throws Exception {
    String appNameStr = new Your_Activity().getResources().getString(R.string.app_name);
    assertThat(appNameStr, equalTo("My App"));
}

4) To test the toast text within the Toast. Remember you have to display a Toast on the button click event.

@Test
public void testToasttext() throws NullPointerException {
    Button btnLogin = (Button) Your_Activity.findViewById(R.id.btnLoginID);
    btnLogin.performClick();
    assertThat(ShadowToast.getTextOfLatestToast().toString(), equalTo("Login Successfully"));
}

5) To test the localised string in specified language, here language = “fr” means FRENCH.

@Test @Config(qualifiers = "fr")
public void testLocalizationStringOfFrench() {
    String strActual = Robolectric.getShadowApplication().getApplicationContext().
                       getResources().getString(R.string.frenchTxt);
    System.out.println("This is the actual string "+strActual);
    assertEquals("Français", strActual);
}

6) To test the audio file is present in raw folder.

@Test
public void testIsFileExistsInRaw() {
    int resourceId = Robolectric.getShadowApplication().getResources()
       .getIdentifier("your_audio_file_name","raw", Robolectric.getShadowApplication()
       .getPackageName());
    if (resourceId != 0) { 
        // Raw folder contains resource.
        System.out.println("The value of Raw ID "+resourceId);
        assertTrue(true);
    } else { 
        // Raw folder doesn't contain resource.
        System.out.println("The value of Raw ID "+resourceId);
        assertTrue(false);
    }
}

7) To test the next Activity started using Intent object.

@Test
public void testIntentStatus() throws Exception {
    ShadowActivity shadowActivity = Robolectric.shadowOf(Your_Activity);
    ShadowIntent shadowIntent = shadowActivity.getNextStartedActivity();
    assertThat(shadowIntent.getComponent().getClassName(), equalTo(Your_Next_Activity.class.getName()));
}

8) To test the putExtras with the Intent object

@Test
public void testPutExtras() throws NullPointerException{
    Bundle extras = Your_Activity.getIntent().getExtras();
    String str = extras.getString("data", null);
    assertNotNull(str);
    assertThat(str, equalTo("This is a Value"));
}

Advantages of Robolectric :

1) Robolectric does not require emulator to run its test cases, makes it fast and easy to execute multiple test cases at one time.
2) Robolectric can fake almost every android related thing as Shadow Objects, each shadow object exposes many useful functions which their normal android counterparts don’t offer.

Limitations of Robolectric :

1) Robolectric does not cover all the functionality a real device or emulator can offer like Sensors, OPENGL etc.
2) For doing integration or UI testing emulator or real device is required.

Happy Coding..!!! 🙂