maandag 26 mei 2014

Robolectric, Gradle and Android - Test Driven Development Part 2

In a previous blogpost I spoke about Test Driven Android Development using Robolectric and a plug-in maintained by Novoda. It did the trick, but failed me short when I was using different productFlavors in my build.gradle script.

Fortunately, a nice team revived the plugin once created by Jake Wharton, which also resolves the annoying problem of the Windows fix you had to foresee.

Quite recently (May 20th) Robolectric also released a stable 2.3 version of their testing library, so it is time to update our build scripts.

Update June 2nd: a new version of Android Studio (Canary Build 0.5.9) has been released. I've updated the blogpost to reflect the updated Gradle version. For more information, please refer to the release notes.

Update June 3rd: the code has been pushed to Github, as described in this post.

build.gradle


buildscript {
    repositories {
        mavenCentral()
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
    }
    dependencies {
        //Prior to AS 0.5.9: classpath 'com.android.tools.build:gradle:0.9.+'
        classpath 'com.android.tools.build:gradle:0.10.1'

        //Prior to AS 0.5.9: classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.9.+'
        classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.10.0'
        //previous plugin >> classpath 'com.novoda.gradle:robolectric-plugin:0.0.1-SNAPSHOT'
    }
}

allprojects {
    repositories {
        mavenCentral()
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
    }
}

apply plugin: 'android'
apply plugin: 'android-test' //previously >> apply plugin: 'robolectric'

android {
    compileSdkVersion 19
    buildToolsVersion '19.1.0'

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug {
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    sourceSets {
        androidTest.setRoot('src/test') //note that this is androidTest instead of instrumentTest
    }
}

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

    androidTestCompile 'junit:junit:4.10'
    //include the stable robolectric 2.3 library
    androidTestCompile 'org.robolectric:robolectric:2.3'
    androidTestCompile 'com.squareup:fest-android:1.0.+'

}

//only include files that are suffixed with Test.class and set the max heap size
androidTest {
    include '**/*Test.class'
    maxHeapSize = "2048m"
}

Your unit tests

With the new plugin, we also need to update our tests. If you run your tests with the standard RobolectricTestRunner, you might see this exception:
be.acuzio.mrta.test.DummyTest > testShouldFail FAILED
    java.lang.UnsupportedOperationException
Your logfiles will probably show you an exception that looks like this:
java.lang.UnsupportedOperationException: Robolectric does not support API level 19, sorry!
 at org.robolectric.SdkConfig.(SdkConfig.java:24)
 at org.robolectric.RobolectricTestRunner.pickSdkVersion(
        ...
You can fix this by adding the @Config(emulateSdk=x) to your class, eg:
package be.acuzio.mrta.test;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;

@Config (emulateSdk = 18) //Robolectric support API level 18,17, 16, but not 19
@RunWith(RobolectricTestRunner.class)
public class DummyTest {
    @Before
    public void setup() {
        //do whatever is necessary before every test
    }

    @Test
    public void testWhoppingComplex() {
        Assert.assertTrue(Boolean.TRUE);
    }
}

Running the tests

Previously you started the tests using:
$ ./gradlew robolectric

Now, you can start the tests using this command:
$ ./gradlew test

The test results will still be stored in your build folder (e.g. /app/build/test-report/index.html).