Autotest by Ryan Davis (aka ZenSpider) is a sweet tool that ships with ZenTest whose job is to keep you informed of test or specification failure as you’re coding your app. Whenever your source files change it reruns the applicable tests and reports the results.
Autotest’s usefulness shines with its dead-simple mechanism for hooking into events such as “test failed” or “all tests passed,” and, as a result, ships with a bunch of useful prebuilt hooks: Autoupdate, Emacs, Fixtures, Growl, Heckle, HtmlReport, Menu, Migrate, Notify, Pretty, RedGreen, Screen, Shame, Snarl and Timestamp.
Configuring autotest is done by simply creating a .autotest file in your project root or home directory. It’s simply a Ruby file, without the .rb extension, defining your hooks or require’ing the ones that ship with ZenTest. ZenTest includes an example config, example_dot_autotest.rb, in the root directory of the ZenTest gem which I highly recommend checking out. Whilst you’re there, have a look inside lib/autotest for the various bits and bobs it ships with.
I’m currently ripping the guts out of legacy app that needs redeploying—yes, I’m adding specs whilst I’m there—so to make life easier for myself I created the following .autotest. I’ve added a custom version of AutoTest::Fixtures and AutoTest::RedGreen to better deal with RSpec’s eccentricities, and Autotest::Speak to speak out test failures via Applescript.
# Just like Autotest::Fixtures, but for specs
module Autotest::SpecFixtures
Autotest.add_hook :initialize do |at|
at.test_mappings['^spec/fixtures/(.*)s.yml'] = proc { |filename, matches|
at.files_matching(/spec\/\w+\/#{matches[1]}(_\w+)?.*_spec.rb$/)
}
end
end
# Just like Autotest::RedGreen, but for specs
module Autotest::SpecRedGreen
BAR = "=" * 80
Autotest.add_hook :ran_command do |at|
# TODO: submit a patch for RedGreen to make the match and code configurable
if at.results.last.match(/^(\d+) examples?, (\d+) failures?$/)
code = ($2 != "0") ? 31 : 32
puts "\e[#{code}m#{BAR}\e[0m\n\n"
end
end
end
# Speak failures via Apple's speech synth
module Autotest::Speak
def self.speak message
system %(osascript -e 'say "#{message}"')
end
Autotest.add_hook :red do |at|
failures = at.files_to_test.size
speak "#{failures} example#{failures == 0 || failures > 1 ? 's' : nil} failed."
end
# Autotest.add_hook :green do |at|
# speak "Specs passed."
# end
Autotest.add_hook :all_good do |at|
speak "All specs passed."
end
end
The possibilities for customising autotest are endless: set up your own continuous integration using Autotest::AutoUpdate with remote-growl, IRC and email notifications; or, write something that uses uses Ruby/SerialPort to make your office’s talking moose head (you do have one, don’t you?) read haiku on behalf of the team member who comitted failing code.
Archived comments
Comments were previously allowed on articles. Though no new comments are being accepted you can see the old comments below.
-
Is a talking moose head anything like a Nabaztag?
Thanks for the article, Tim. I get the feeling I’m going to need lots of tests for my work :)
-
omg it’s a talking rabbit with lights and an API!!! I’m so buying one of these.
-
The applescript say hook is super cool. Didn’t think of doing that, Growl notify still takes away the attention.
-
I gotta dig into this stuff more. Autotest was my only stumbling block when I added namespaced functional tests to my project. I discovered that it got the mapping right if I appended
Testto my module name. At the time I just needed the tests to work, but this is inspiring all kinds of other ideas. -
Thanks for the props!
FYI, osascript isn’t needed. `say` is a command line as well.
Also, please merge your redgreen into mine and submit a patch. No reason for a second plugin if it is just regexp differences.
-
Rex: yeah, I much prefer more subtle signals for CI testing on my machine… leave the alarm bells for the team CI buids.
Gabe: I’m sure you could adapt the
AutoTest::SpecFixturesto detect changes correctly for your application.Ryan: a command line ‘say’. Cool! If I can’t figure out a way for the regexp to live inside the rspec related part of autotest I guess I’ll just extend the built-in regexp. It’s tricky not being able to ‘require’ a plugin to configure it w/o actually activating it.

