Given that the target machine for an Android app is an Android VM the only real way of running any tests is in the emulator. This seemed like a very complex operation especially for unit tests on individual method calls. There are test that I would only want to run in an emulator or a device such as UI testing but I like to test base components before I get into assembling them as it tends to eliminate bugs while I am writing the base objects and produces a stable product.

In MeasureMe I have used the RoboElectric unit testing framework as it enables me to test my pure java business objects outside the emulator just using JUnit syntax. My background is NUnit so I find it most natural to use the JUnit syntax.

To add the unit tests to MeasureMe I found this page had an excellent description on how to get started. Including a ZIP file with all the required JARs in, I then replaced the RoboElectric JAR with the most recent release on Maven Central. Or you could just get them from the MeasureMe source.

Then just

  1. Create a plain Java project called MeasureMeTests, I put it in a folder called test as I may add UI tests in the future
  2. Add MeasureMe (the native android app) as a project reference
    project references
  3. Add the following library references, I don't do anything more complicated than copy the jars into the lib folder of the test project and then reference the jars. You do need to make sure that the JUnit jar is added before the Android jar
    libraries

The sort of code that I wanted to test is the alarms in MeasureMe. Alarms can be set to trigger with a wide variety of intervals from 1 second to 52 weeks and by using day and hour masks the alarms can be supressed at particular times and on certain days. This is complex and easy to get wrong so I wrote tests like this

package net.derekwilson.measureme.model.alarm;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import net.derekwilson.measureme.AndroidTestRunner;
import net.derekwilson.measureme.model.Alarm;
import net.derekwilson.measureme.model.Interval;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidTestRunner.class)
public class NextTriggerTests {
 protected Alarm GetSUT() {
  return new Alarm(GetNow());
 }
	
 protected Calendar GetNow() {
  Calendar cal = Calendar.getInstance();
   cal.set(Calendar.AM_PM,2);
   cal.set(Calendar.YEAR,2014);
   cal.set(Calendar.MONTH,3);
   cal.set(Calendar.DAY_OF_MONTH,16);
   cal.set(Calendar.HOUR,20);
   cal.set(Calendar.MINUTE,15);
   return cal;
 }

 @Test
 public void Next_Trigger_After_1_Hour() {
  Alarm alarm = GetSUT();
  alarm.setInterval(new Interval(1,Interval.STRIDE_HOUR));
  assertThat(alarm.getNextTriggerTimeFormatted(GetNow()), is("Thu 17 Apr at 21:00"));		
 }

 @Test
 public void Next_Trigger_After_1_Hour_With_Hour_Mask_Of_1_Hour() {
  Alarm alarm = GetSUT();
  alarm.setInterval(new Interval(1,Interval.STRIDE_HOUR));
  alarm.setHourMask(0x6FFFC0);
  // mask forces the trigger onto 10pm
  assertThat(alarm.getNextTriggerTimeFormatted(GetNow()), is("Thu 17 Apr at 22:00"));		
 }
}

Running the tests can easily be dome from Eclipse, I just use the standard JUnit runner.