Adding pure Java unit tests to an Android project

This post has a very slim target audience: developers who

  • are not familiar with gradle
  • are not familiar with android development
  • have some exposure to Java (enough to create a class)
  • have done mobile development (Windows Phone/iOS)
  • are interested in writing "pure" unit tests for Android
  • are working with an existing Android project that succesfully builds and runs

If you meet all those criteria, come join me on a journey that seems (mostly) poorly documented. Perhaps I haven't been searching for the right terms, but regardless I'm going to put my findings here. I'm currently using Android Studio 0.8.9.

We will assume the following project struture for the android app. The libraries folder is completely optional; the main thing is that the android-dependant app source code is in src.

$/
|-app
  |-build
  |-libraries
    |-facebook
  |-src
    |-androidTest
    |-main
      |-assets
      |-java
          |-com.....
      |-res
    - build.gradle
- build.gradle
- settings.gradle

Here's what we want to accomplish:

  1. add a "regular" or "pure" Java module so that it can be used by the Android application
  2. be able to write jUnit tests for this module and then run these tests from Android Studio

1. Adding the Java module

  • Create a pure directory under libraries.
  • Create a src/main/java directory under pure (for source code). Under that, create the appropriate com.example.pure directory.
  • Add an empty Java class to the last-created directory (for this example, I'm using MyClass)
  • Create a file called build.gradle in your pure directory. It only needs to contain a single line: apply plugin: "java".

(Note: if you have the 1.8 JDK installed, you have to force your pure Java module to use 1.7, as that's what Android currently supports. If you do not, you will get a very weird build message like [ERROR] bad class file magic (cafebabe) or version (0035.0000). To do this, add the following two lines to build.gradle:

sourceCompatibility = 1.7  
targetCompatibility = 1.7  

We now have this:

$/
|-app
  |-build
  |-libraries
    |-facebook
    |-pure
      |-src
        |-main
          |-java
            |-com...
              SampleClass.java
      - build.gradle
  |-src
    ...
- build.gradle
- settings.gradle
  • To get our module to build, update settings.gradle in the root folder.
include ....., ':pure'  
project('pure').projectDir = new File('libraries/pure')  

At this point you should be able to build your app and new module successfully.

Using the module from an Android app

We can ensure the "pure" module is accessible from our Android application by attempting to use it.

  • In $/app/build.gradle, add compile project(':pure') to the dependencies section.
  • Android Studio will probably tell you it needs to sync (let it). If you look at the Gradle Console, you should see :pure:compileJava, :pure:processResources, :pure:classes and :pure:jar in the output.
  • Reference your new object from any class in your Android application. It should still build and run as before.

2. Adding jUnit tests

  • Give your sample class an add() method that takes two integers and returns their sum. We need something to test :)
  • Add the following to build.gradle (the one in pure)
dependencies {  
    testCompile group: 'junit', name: 'junit', version: '4.11+'
}

(I'm assuming your main project already has repositories setup. If not, add repositories { jcenter() } as well.)

  • Create a new class in $/libraries/pure/src/test/java/com.... (For this example, I have MyClassTest). Make sure it is public.
  • Add a test to it. As an example, here's what I have:
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class MyClassTest {

    @Test
    public void testAdd_CanAddTwoNumbers() {
        MyClass sut = new MyClass();

        int result = sut.add(3, 4);

        assertEquals(7, result);
    }
}
  • Make sure everything still builds.
  • Right-click on your class and choose 'Run {MyClassTest}'. The output should show "all tests passed."
comments powered by Disqus