Running Android instrumentation and automation tests with Gradle

We here at Redfin are always trying to stay on top of the latest trends in Android development. Admittedly, it’s pretty hard given the pace that Google releases developer tools. The open source community moves at an even faster clip, releasing incredibly useful frameworks on top of Google’s own offerings. We’re big fans of Roboguice and Robotium. We recently starting using Mockito and Dexmaker for mocking in unit tests. When we find the time, we’d love to add some of Square’s great projects, including OkHttp and Picasso, to our codebase.

When Xavier Ducrohet introduced the new Android build system at Google I/O back in May, we were excited to try it out. We had been tied to Maven since we first released our Android app back in 2011. It had been a useful tool for us, but doing anything out of the ordinary required a great deal of effort. Modifying strings for Google and Amazon releases was a pain, as was switching dev and prod API keys as part of the build. The new Gradle build system made these tasks trivial. The combination of Android Studio and Gradle finally gave us the power to easily perform tasks that were challenging with Eclipse and Maven. Becoming early adopters was somewhat harrowing, but that’s a blog post for another day.

Prior to migrating to Gradle, our app, unit/instrumentation tests, and automation tests were in 3 separate Maven projects. We ran our automation tests nightly and our unit/instrumentation tests when code changes were committed. Even when every other part of the build system was a mess, this part was simple.

Android’s Gradle build system combines app and test code under the same directory structure. App code lives in Redfin/src/main/java, while test code is in Redfin/src/instrumentTest/java. What happens to automation test code though? Since these tests take close to an hour to run, adding them to the test directory wasn’t an option. I raised this issue on the Android Developer Tools Google+ page and later on the adt-dev forum. Big thanks to Xavier Ducrohet for taking the time to discuss our problem. We’re waiting on support for @Small/Medium/Large annotations on tests. Until then, we needed a hack.

I started looking for a solution in the build system source code before realizing that this was a bit crazy on my part. An easier solution was just to hack around the directory structure of the build system. We structured the tests like so:

        instrumentTest (unit/instrumentation tests)
        automationTest  (nightly automation tests)

On a regular continuous build, the automation tests would simply be ignored. When we want to run these tests, we just copy them into the instrumentTest folder under the right package name.

Our script for regular unit/instrumentation tests:

#!/bin/bash -x

# Clean and run instrument tests
./gradlew clean --info
./gradlew connectedInstrumentTest --info

Our script for nightly automation tests:

#!/bin/bash -x

# This script is a temporary hack to keep the automation tests separate
# from the regular instrument tests. The end goal is to use
# @Small/Medium/Large test annotations to pass into the test runner,
# but Gradle hasn't implemented that functionality yet.

# Clear the previously copied Robotium tests 
# in case they're hanging around
rm -rf src/instrumentTest/java/com/myexample/robotium

# Move the automation test files over from the separated folder
cp -r src/automationTest/java/com/myexample/robotium src/instrumentTest/java/com/redfin/android/

# Run the unit tests with Robotium. Only point of this script 
# where we want to break on errors
set -e
./gradlew clean --info && ./gradlew connectedInstrumentTest --info
set +e

# Clear the copied Robotium tests
rm -rf src/instrumentTest/java/com/redfin/android/robotium

It’s not pretty, but it has comments and gets the job done. If you’ve had better luck with a similar problem, we’d love to hear about it in the comments.


  • This Is Bullshit

    This is probably the most worthless piece of information on this subject I have ever read. It contains no relevant information whatsoever.