Set up an Android Project with Robolectric

Reading Time: 4 minutes

In this post, I’ll go over how to configure a brand new Android app to use Robolectric.

The topic of why a developer might want to do TDD is for other posts. This is strictly a how-to on setup.

Two things involved:
1. Make a new Android project
2. Include Robolectric (a unit testing library for Android)

robolectric
1. Make a new Android Project

I develop for Android in Android Studio, a fork of the community version IntelliJ (a JetBrains-made IDE for Java). When you open Android Studio, you get a wizard that will help you set up an Android project. I believe that Eclipse provides the same. You will receive the option to make an app with a Blank Activity out of the box. You can either do this, or you can create your app with no activity to start, then create a class in src/main/java that extends Activity and add the name of that class to the Android Manifest. For this example, I called my Activity MainActivity, and it looks like this:

public class MainActivity extends Activity {
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 }

2. Include Robolectric

Robolectric allows automated testing in Android by giving us control over the state of the app and the life cycles of the activities. To get it, we add it to the dependencies in our app’s build.gradle like so:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion '21.1.2'

    defaultConfig {
        applicationId "com.example.macowner.practiceapp"
        minSdkVersion 21
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    dexOptions {
        jumboMode true
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'

    compile 'com.squareup.dagger:dagger:1.2.2'
    provided 'com.squareup.dagger:dagger-compiler:1.2.2'

    testCompile 'junit:junit:4.12'
    testCompile('org.robolectric:robolectric:3.0-rc2') {
        exclude group: 'commons-logging', module: 'commons-logging'
        exclude group: 'org.apache.httpcomponents', module: 'httpclient'
    }
}

You’ll notice a couple of differences between your out-of-the-box build.gradle and the one shown here, other than the robolectric and junit dependencies listed in testCompile. You see multiDexEnabled, minifyEnabled, proguard, and jumboMode. Without these, you will struggle to run your first Robolectric test because the Robolectric library puts you past the Android framework’s 65,000 method limit. Trust me, you get some weird-looking errors when you go to run your test.

The test itself:

I made an example test to run so I could make sure Robolectric was working. My MainActivity has an associated layout in src/main/res/layout that looks like this:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/hallo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hallo warld" />

</RelativeLayout>

I have a text view with an id, and I’ll be checking the text inside of it in my test. I, my activity, I don’t actually do anything to the text in that text field. Given that my program does not do anything to this text field, it’s not a great candidate for an automated test. We just want something that we can test, regardless of whether or not we’d bother to test it in an app, so we can make sure we hooked up Robolectric correctly.

Next, I made a file in src/main/test/java called MainActivityTest:

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, emulateSdk = 21)
public class MainActivityTest {
    private MainActivity activity;

    @Before
    public void setup() throws Exception {
        activity = Robolectric.setupActivity(MainActivity.class);
        assertNotNull("MainActivity is not instantiated", activity);
    }

    @Test
    public void validateTextViewContent() throws Exception {
        TextView helloWorldView = (TextView) activity.findViewById(R.id.hallo);
        assertNotNull("TextView could not be found", helloWorldView);
        assertTrue("TextView contains incorrect text",
                "hallo warld".equals(helloWorldView.getText().toString()));
    }
}

You see two annotations on the top. The first one runs the test class with RobolectricGradleTestRunner so it knows how to use the Robolectric methods we’ll be using. The second one provides a version of the Android SDK for Robolectric to use when simulating calls to the Andoid OS.

In the setup, we call Robolectric.setupActivity on the activity we want to test. Then in the test, we find our view and make sure that the text inside of it is “hallo warld.” It passes. Yay! If we change the text in our layout, it fails. This is a good sign, too.

So we now have an activity with a test file. Inside of this test file, we can continue to test how our activity works.

Next, I’ll try to set the thing up with Dagger 2. If that succeeds, I’ll post on how to do that. In the meantime, my coworker Tony Tarantini has provided a starter repo on Github for an Android project with Robolectric and Dagger 1.2.

 

One comment

Leave a Reply to dineshramitcCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.