“Continuous Integration is a hack!” said my friend Ben Rady years ago during a discussion on CI hosted by Stelligent. At the time, I was incredulous! How dare someone question the value of CI, especially when we had just finished writing a book about it! What’s more, our book had been nominated for a prestigious Jolt award; indeed, the following day, our CI book won it!
In retrospect, Ben’s point was poignant: CI is reactionary. You still have to wait some amount of time to ascertain correctness. That is, CI implicitly relies on a passive process to run a project’s build and any corresponding tests. If those tests fail, you are of course, notified. Nevertheless, that notification is somewhat delayed: by the time a CI process runs the tests and reports on their status, you’ve already moved on to the next task. So much for failing fast!
A more proactive means to ensuring all is kosher with a code base is to continuously run your tests as you work. In fact, an even more superior process would be to run any tests for code that has changed. That is, once a mapping has been established between code under test and a corresponding test, then when that code changes, the quickest, arguably most effective way to ensure that code isn’t broken is to run its test(s).
One efficient way to ascertain mapping is to name tests after the code they verify proceeded with a
test moniker. For example, an
Account object would have its corresponding test called
AccountSpec, etc). Any time the
Account object changes, then the
AccountTest would be run.
Continuous Testing is an established practice in the world of Ruby. A great framework that facilitates it is called Guard. Briefly, Guard is a framework for watching a file system and sending out a notification upon some event (like a change). With Guard, you can define specific file matching patterns and a corresponding action to take when an event is triggered. You can probably see that this linkage facilitates running tests continuously.
There’s really no corollary framework or tool in Java (other than Infinittest and other IDE tools). Nevertheless, you can use Guard to continuously test a Java project. I wrote about how to do it with an Android over two years ago and about 6 months ago I got involved in a Guard plugin for Gradle, dubbed Guard::Gradle.
To use Guard::Gradle, you’ll need to have Ruby installed. For those on OSX, you already have Ruby. Once you have Ruby installed, the installation of Guard::Gradle couldn’t be more easy: just open up a terminal in your desired Gradle project and type:
The above command will download a script and execute it. That script will:
- Install Ruby’s Bundler
- Install the Guard::Gradle plugin
- Create a default
- Create a Guard launcher script, dubbed
Therefore, after you run the above command, just execute
guard.sh to start Guard::Gradle! Any time you change a file in your source tree, a corresponding test will be executed using the Gradle
Guardfile assumes a standard Gradle project setup, with source code located in
src/main. In fact, if you are curious, take a look at the generated
Guardfile and you’ll see:
1 2 3
watch command examines the
src/main directory and attempts to execute a matched file’s test. If no test is found, all tests are run. So either way, if a change happens, you’re covered with some amount of tests.
which ostensibly updates your local directory with all upstream changes). Consequently, if upstream changes have broken your local branch, you’ll know instantly. No more need to remember to “run the tests” – they’re always running.
Of course, Continuous Integration isn’t a hack. But Ben made a prescient point back then: if you want to fail fast and shorten the time to detect failures, why not do it at the source? Why not know instantly while you’re working instead of some later time after you’ve moved on? Assuming your project has tests, then Continuous Testing is the answer. Continuous Testing is the proactive yin to CI’s reactive yang.
Check out Guard:Gradle today and know instantly when you’ve made a breaking change! Now that’s something everyone can dig, right?