Continuous Android testing with Guard

Because it’s my bag, I’ve been spending a lot of time these days deep in Ruby code. Nevertheless, from time to time, I do find myself ensconced in Java via the Android platform. Jumping back and forth between various languages like Ruby, Java, and JavaScript can be a lot of fun; what’s more, doing so broadens one’s view on various practices, idioms, and influences conveyed by a particular community.

Something that I found missing in Java’s community, in the form of a concrete easy to use library, is something like Ruby’s Guard. Guard is “a command line tool to easily handle events on file system modifications.” In essence, Guard makes continuous testing possible with a minimum amount of effort.

For example, with Guard, you can create a Guardfile that watches your file system (naturally, you can select which types of files to watch — .rb files, etc); what’s more, when those target files change (i.e. you added some code) a trigger can be invoked, such as running a test suite, invoking a Rake command, etc. Thus, with Guard, you can set up a process that executes a test suite (or an individual test) whenever you change a source file — this alleviates you from having to manually invoke a Rake task or do something else to trigger a test run.

As you can imagine, once you’ve set this up, it becomes highly addictive — why would anyone ever manually invoke Rake test again? It’s always running anyway!

Setting up Guard to invoke Ant, for example, couldn’t be any easier. You first must have Ruby installed, followed by RubyGems and Bundler. Next, in your Gemfile, you need to include guard as follows:

source :rubygems

group :development do
  gem 'guard'
  gem 'growl'
end

Because I’m on a Mac, I’m also using Growl, which is an OS-level notification mechanism (i.e. a popup dialog that informs you that your test suite has passed, failed, etc).

Next, you need to create a Guardfile — in this case, I’m going to create an inline Guardfile as there isn’t a plugin available (yet) to support running something like Ant. My inline Guardfile looks like this:

require 'guard/guard'

module ::Guard
  class Ant< ::Guard::Guard
    def run_all
      invoke_ant
    end

    def run_on_changes(paths)
      invoke_ant
    end
    
    def start
      invoke_ant
    end

    def stop
    end
    
    def invoke_ant
      system 'ant clean test'
    end
    
  end
end

guard 'ant' do
  watch(%r{^src/*/(.+)\.java$}) 
end

As you can see, this Guardfile simply watches any .java file and if any change, run’s ant clean test — the Guard base class is fairly straightforward — there are a series of hook methods you can implement. In this case, start is called the first time you fire up Guard. run_on_changes ideally is used to run a single test as you have access to the incoming file path of what’s changed; however, in this case, I’ve chosen to run the suite again as parameter passing into Ant & invoking a special JUnit task with single tests is somewhat painful (but it could be certainly done). Finally, run_all is called at special points, such as after you fix a failing test, etc. In essence, these are lifecycle methods and you have complete control over what happens when they are invoked.

Continuous testing in Java isn’t new. Yet, it seems that the wealth of tools and thought regarding continuous testing results in a shift towards Continuous Integration or worse, the IDE. For instance, a simple search on continuous testing tools in Java yields Infinitest and JUnit Max — both are great tools (Ben Rady, the original Infinitest guy is one of the sharpest guys I know). These tools, however, are plugins for an IDE, like Eclipse. I abandoned Eclipse some time ago in favor of IntelliJ (and Infinitest certainly supports IntelliJ); thus, these days, I do all Android development using IntelliJ, however, I tend to rely on Ant for building Android artifacts (even though there is a Maven library for Android).

In the end, I want an easy way to continuously run tests — if they can be run anytime I change a file, excellent. So long as I don’t have to manually kick off an Ant/Rake/Cake build, then the better. Can you dig it?

Related: