Sunday, May 5, 2013

Testing with Robolectric in Android

This is a quick guide of how I set up a testing environment for our Android application.

We use Robolectric and Mockito instead of the android tools. The key benefit of this setup is the *speed*: tests run in a Java Project, bypassing the emulator (android tools make tests run in the emulator).

Maven: not today

Robolectric documentation advices to install it thorugh maven. However I was unable to mavenize our project. In fact, making Eclipse (we use eclipse) to play nice with maven corrupted my ADT twice. So, we will use robolectric without maven.

Preparation

Make sure that your android tools are in the system path. Open a terminal, if android -h is not recognized then you have to get the path of yout tools, and the update your .profile or .bashrc with somelink like these lines at the end (use your path):


ANDROID_HOME=/home/jesus/bin/adt-bundle-linux-x86_64/sdk
export ANDROID_HOME

PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
export PATH
 
reload your profile: source ~/.profile 

I recommend you to download the source code of Robolectric from https://github.com/pivotal/robolectric and the sample project and a sample project https://github.com/pivotal/RobolectricSample . I use them as documentation when official fall short.

Note that we can use the pom.xml in the robolectric project ( https://github.com/pivotal/robolectric/blob/master/pom.xml ) to know which versions of each library are safe to use when downloading the dependencies. I call it the pom trick.

Eclipse project

This is key to understand. Robolectric runs as a java application, not as an android application. So our test project will be a Java project, not an android project or an android test project. Our run configuration will be a Java junit configuration, not an android test run configuration. We see it now.

Create a new Java project File >New > Java Project . I name it as my Android project to test + 'Test'. For example Microhealth and MicrohealthTest. This new project will be our test project vs the android project. Finish.



Create a folder called libs where we put the libraries we need to run robolectric. I usually do it in the file explorer and the I press 'Refresh F5' in eclipse. What libraries do we need? It might change with newer versions of robolectric, but at least:
- Robolectric. Get it from http://pivotal.github.io/robolectric/download.html ( that in turn redirects to sonatype ) Download the latest robolectric-X.X.X-jar-with-dependencies.jar In my case I using robolectric-2.0-alpha3-jar-with-dependencies.
- Junit 4: We need Junit 4 from http://junit.org/  Not all versions are compatible with Robolectric. I am using now junit-4.10.jar and discarded newer versions. (or use the pom trick i described before)
- Mockito: get mockito-all-1.95.jar from http://code.google.com/p/mockito/downloads/list
- android.jar:  get it from your android installation got to your sdk_root in sdk root/platforms/android-9/android.jar (I am using the 9 as the min version, change it to yours)
- in case you need maps: get maps.jar from sdk root/add-ons/addon-google_apis_google-9/libs/maps.jar I usually skip this part.
 - FEST libs. These are required by robolectric to make writing tests less verbose. It tookme some time until I get the right versions of FEST but you can use the pom trick as well. fest-assert-core-2.0M10.jar and fest-util-1.2.5.jar (download from http://mvnrepository.com/artifact/org.easytesting/fest-assert-core/2.0M10 )
- hamcrest-all:  hamcrest-all-1.3.jar from http://code.google.com/p/hamcrest/downloads/list

Once you have all of them in your test project /libs folder. Declare you wnat to use them: right click on the test project > Properties > Java build path > Libraries > Add Jars and add them.

Make sure that robolectric and its dependencies (including JUnit) appear before the Android API jars in the classpath. In the properties > Order and export > move the android.jar and maps.jar after all other libraries


Require you android project in the build path. Make sure than Properties > Java build path > Projects,  references to you android project (Add > your android project)

Thats all. Now are going to test our setup.

(I found the official guide a bit outdated http://pivotal.github.io/robolectric/eclipse-quick-start.html , but maybe it works better with older robolectric versions)

Our first test

create a new class in the test project. This will contain out first test. Something like:


package com.microhealth.test.testicle;

//Let's import Mockito statically so that the code looks clearer
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

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

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;


@RunWith(RobolectricTestRunner.class)
public class FooTest {
  
  @Test
  public void testDummmy() throws Exception {
    assertTrue(true);
  }
  
  
  @Before
  public void setUp() throws Exception {
    //no need to setup nothing
    
  }
  
}

The test MUST be run as a Junit test NOT as an android test. Go to Run > Run Configurations menu, and create a new JUnit test configuration (the name is not important).  Do not create an ‘Android JUnit Test’.
  • Set the test runner as JUnit 4. (tab test)
  • check the 'Run all tests in the selected project, package or source folder' and choose your test project. (not the android project)
  • Locate at the bottom, the link:  Multiple launchers available — Select one….  Click the Select other… link, check Use configuration specific settings and choose Eclipse JUnit Launcher. Remember taht the test project runs as a Java project, we dont want it to run as an Android one.
  • in the 'Arguments' tab, configure the working directory as the android directory. In the 'Working directory' section, check 'Other' > 'Workspace' and locate your android project. Select it.
Click on 'Run' to save and make your tests run. If everything is ok, your first test run and pass. 


I write a future post I will explain how to set up tests to run a project that depends on DataDroid and ActionBarSherlock.

7 comments:

  1. It helped me a lot, thanks! I was having problems with Roboelectric in Eclipse, and your post was very helpful.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Thanks for the post with simplified approach.
    I was successful following these steps. But when I wrote this to test my Activity ,I got exception
    mockActivity = new MockActivity();
    mockActivity.onCreate(null); //fails during setContentView call.

    java.lang.NullPointerException
    at org.robolectric.shadows.ShadowContextWrapper.getApplicationInfo(ShadowContextWrapper.java:192)
    at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java)
    at android.view.ViewGroup.initViewGroup(ViewGroup.java:447)
    at android.view.ViewGroup.__constructor__(ViewGroup.java:417)
    at android.view.ViewGroup.(ViewGroup.java:416)
    at android.widget.FrameLayout.(FrameLayout.java:93)
    at org.robolectric.tester.android.view.RoboWindow$1.(RoboWindow.java:218)
    at org.robolectric.tester.android.view.RoboWindow.getDecorView(RoboWindow.java:218)
    at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:80)

    ReplyDelete
    Replies
    1. Sorry, I've been disconnected for some time.
      In latest versions of Roboelectric, you should instantiate the activity in the setUp method. Something like

      public void setUp() throws Exception {
      super.setUp();

      mockActivity = Robolectric.buildActivity(MockActivity.class).create().get();
      fooRes = (EditText) loginActivity.findViewById(R.id.fooRes);
      ...
      }

      Delete
  4. Thank you very much for the post. Nice article :)
    I am trying to setup Robolectric 2.1.1 jar with-dependencies in Eclipse(without maven). But unfortunately i get
    Downloading: org/robolectric/android-base/4.1.2_r1_rc/android-base-4.1.2_r1_rc.pom from repository central at http://nexus:8081/nexus/content/groups/build.snapshots/ in console and hence not able to run my tests.
    My tests fails saying unable to resolve artifact org.robolectric:android-base:jarreal:4.1.2_r1_rc
    Is there something which I am missing. Please help me out.
    But the tests are green if i use the older releases of robolectric jar. (Eg : 1.X.X jar with dependencies) Clueless as to why this is happenning.
    Could you please guide me if possible.

    ReplyDelete
  5. Hi,
    I have also tried to follow this guide but is getting the same error as Madhushree. It looks like it tries to download its dependencies with Maven.

    ReplyDelete
  6. HI! It's really doesn't work with new version of robolectric. How to fix this?

    ReplyDelete