Autotest doesn’t work, for me. Hello Watchr

iStock_000004453604XSmallI wanted to use Autotest for testing. So many Podcast, screencast and even conference talks have shared that if you are not using AutoTest, you should be.

It’s understandable that so many love Autotest. 4 out of 5 dentist even recommend using it. It so much easier and faster to know if the code/scripture you are writing, is FAIL coded. But I cannot use Autotest. Here is why.

IT SUCKS! No, just kidding. This is not going be a ghetto rants. No really, heres why I can’t use AutoAwesome.

When I start working on a new Rails project, I start from a foundation. Rails templates allows me pull in all the plugins, initializers and configurations. One of the plugins pulled in, is a custom in-house CMS. I separate project specific additions out into new plugins/engines. So as you might can see, most of my work is not done within the main “app” folder, and most of my tests are not in the project’s main “test” folder. With any projects that uses this in-house CMS, the goal really is to not have any code in the main “app” folder. everything should be separated and self contained within its engine.

Reuse. That’s the key. I don’t care for reinventing the wheel. I would much rather drag and drop a plugin, then have to pull and untangle some functionality into a new project.

Back to Autotest. Please note that when I speak of Autotest, I’m including Autotest-rails. By default AT ignores the /vendor folder. This make sense. When running your test you wouldn’t want to also run the plugin tests. There’s a level of trust that we have for many plugins. That these plugins have their own tests. Also, should we want to test the plugins, it would be purposed.

rake plugins:test

Autotest is configurable. Should you want, you can tell AT which file matching patterns it should watch.

Autotest.add_mapping

The add_mapping method is a lot of what makes up the Autotest-rails plugin. Seeing this, EURIKA! I have a plan, use add_mapping. Setting up for the simplest trial, of getting Autotest to work with my Rails Engine, I added this to .autotest:

Autotest.add_hook :initialize do |at|
at.add_mapping %r%^vendor/plugins/case_studies/app/controllers/admin/case_studies_controller.rb$% do |_, m|
"test/functional/admin/case_studies_controller_test.rb"
end
end

Oh, I can’t wait, I’m about to OWN this issue. Yep, testing paradise HERE I COME! I run to the command line, change directories into my project, and fire up Autotest. After making a simple edit to my admin controller, I receive this annoying little message.

Unable to map class Admin::CaseStudiesControllerTest to a file

broken stop signWhat do you mean “Unable to map”. I told you(Autotest) were to map. Thus my new quest has been discovered. Yes, much like some of our greatest explores of times past, Columbus, Lewis and Clark, I have no “X” on a map, only an “X”.
I must know what causes this “Unable to map”.

I started by digging around in the Autotest code. After a while, I finally learned that Autotest doesn’t understand namespacing. If I were to move the test down a folder and remove the “Admin” namespace, Autotest is happy. But for my needs this will not work. I must have the test live in the admin folder with the admin namspacing.

I set out to asked the IRC channels, all I go was silents. I asked the forums and stackoverflow and as of today 0 replies. I am left with out a solution. But then, I see a little flash in the distance, as I get closer, I see that its another file change detection and testing tool called watchr.

Watchr. Is the answer I have been looking for. Its simple. It doesn’t cared about mappings. It cares about patterns. Patterns you give it to detect, and patterns it should act on. Here is how I installed and use watchr.

Installing Watchr

gem install watchr --source http://gemcutter.org

you might consider installing ‘redgreen’ as well.

gem install mynyml-redgreen --source http://gemcutter.org

Configuration
Add an ruby config file to your project root. The follow was based upon an watchr included test:

# --------------------------------------------------
require 'rubygems'
 
def run(cmd)
puts(cmd)
system(cmd)
end
 
def run_all_tests
# see Rakefile for the definition of the test:all task
system( "rake -s test:all VERBOSE=true" )
end
 
watch( '^vendor/plugins/(.*)/app/controllers/admin/(.*)\.rb')   { |m| run( "ruby -Ilib vendor/plugins/#{m[1]}/test/test_helper .rb -Itest vendor/plugins/#{m[1]}/test/functional/admin/%s_test.rb"  % m[2] ) }
watch( '^vendor/plugins/(.*)/test/functional/admin/(.*)_test\.rb')   { |m| run( "ruby -Itest %s"                                                  % m[0] ) }
 
watch( '^vendor/plugins/(.*)/app/models/admin/(.*)\.rb')   { |m| run( "ruby -Ilib vendor/plugins/#{m[1]}/test/test_helper -Itest vendor/plugins/#{m[1]}/test/unit/admin/%s_test.rb"             % m[2] ) }
watch( '^vendor/plugins/(.*)/test/unit/admin/(.*)_test\.rb')   { |m| run( "ruby -Itest %s"                                                        % m[0] ) }
 
watch( '^vendor/plugins/(.*)/app/controllers/(.*)\.rb')         { |m| run( "ruby -Ilib vendor/plugins/#{m[1]}/test/test_helper -Itest vendor/plugins/#{m[1]}/test/functional/%s_test.rb"        % m[2] ) }
watch( '^vendor/plugins/(.*)/test/functional/(.*)_test\.rb')   { |m| run( "ruby -Itest %s"                                                        % m[0] ) }
 
watch( '^vendor/plugins/(.*)/app/models/(.*)\.rb')   { |m| run( "ruby -Ilib vendor/plugins/#{m[1]}/test/test_helper -Itest vendor/plugins/#{m[1]}/test/unit/%s_test.rb"                         % m[2] ) }
watch( '^vendor/plugins/(.*)/test/unit/(.*)_test\.rb')   { |m| run( "ruby -Itest %s"                                                              % m[0] ) }
 
# --------------------------------------------------
# Signal Handling
# --------------------------------------------------
# Ctrl-\
Signal.trap('QUIT') do
puts " --- Running all tests ---\n\n"
run_all_tests
end
 
# Ctrl-C
Signal.trap('INT') { abort("\n") }

Running Watchr
The project page says that watchr should have installed in your path after installation, but that didn’t happen for me. I added a symbolic link to the executable watchr.rb

ln -s /Library/Ruby/Gems/1.8/gems/watchr-0.5.9/bin/watchr /usr/local/bin

From your project root run:

watchr project.rb
iStock_000008970603XSmallThis works pretty well for me. At some point I would like to get growl working with watchr. I started out hoping to get Autotest to work for my situation, but ended up just glad there was a solution.

Thanks Martin

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • bodytext
  • del.icio.us
  • Google
  • StumbleUpon
  • Technorati
  • description
  • Facebook
  • Reddit
  • Slashdot
  • TwitThis

This post was written by .

More Posts by   Visit 's Website

3 Comments

Join the Conversation

  1. Ryan Davis says:

    Not entirely accurate. autotest maps X::Y::Z to TestX::TestY::TestZ, not X::Y::TestZ. This is because it DOES understand namespaces and wants to keep test namespaces rigidly separated from implementation namespaces. TestZ shouldn’t be accessing implementation namespaces that it is enclosed in, and if it does, it can result in false negatives and false positives.

    • admin says:

      Awesome, I have been hoping someone would reply with a solution for the namespace autotest. I will give this a try. Thanks for taking the time to reply.

  2. David Reese says:

    I spent a lot of time setting up autotest to test engines — including engines with migrations.

    I wrote it up here: http://code.whatcould.com/2009/02/09/gentlemen-test-your-engines.html

    But since then have upgraded autotest (including my own fork, which adds a critical hook) so the instructions might not be exactly precise. Let me know if you try it and have issues.

Leave a Reply