limiting scope of autotest
March 5th, 2008
If you use autotest with rspec or test/unit, you’ve probably had this experience (or one like it):
You want to add some new behaviour to a model object, so you write a spec, watch it fail, make it pass, and then wait until the entire spec suite runs. Even if you’ve got a fast-running suite, this can be painful sometimes.
Wouldn’t it be great if you could limit the scope of what directories autotest observes? Well it turns out that you can! Recent releases of ZenTest include a find_directories attribute on the autotest object. Just add this to your .autotest file:
Autotest.add_hook :initialize do |at| unless ARGV.empty? at.find_directories = ARGV.dup end end
and then you can say:
autotest app/models spec/models
and it will only observe those directories. This is nice and flexible, but I find that most of the time I’m wanting pairs like that: app/models and spec/models, or app/views/accounts and spec/views/accounts. In that case, I’d really like to just say:
autotest models
To accomplish that you can do this to the hook instead:
Autotest.add_hook :initialize do |at|
unless ARGV.empty?
at.find_directories = ["spec/#{ARGV.first}","app/#{ARGV.first}"]
end
end
Want the best of both worlds? Try this:
Autotest.add_hook :initialize do |at|
unless ARGV.empty?
at.find_directories = ARGV.length == 1 ? ["spec/#{ARGV.first}","app/#{ARGV.first}"] : ARGV.dup
end
end
The only limitation of this is that it’s based on directories, not files. Once in a while, when I’m bootstrapping a new object, I’ll keep the examples and the implementation in the same file until I’ve got things fleshed out a bit the object is ready to play nice with others. In that case, I might like to just point autotest to that one file. I started working on a patch for this for ZenTest, but I’m not sure it’s worth the extra effort. What do you think?
Regardless – happy auto-exemplifying!



March 5th, 2008 at 2:07 am
Don’t you just do
to skip the full run when autotest starts. Then it just runs the files that change.
March 5th, 2008 at 2:07 am
Nice trick David!
def make_test_cmd(files_to_test) return "#{ruby} -S #{spec_command} #{add_options_if_present} #{execute_latest_failure} #{files_to_test.keys.flatten.join(' ')}" end
def execute_latest_failure "-e 'CommunityController (when the session has been resetted) AJAX add_country should not throw exception'" end
Doing that, Autotest could run that only spec in 5s only instead of almost 45s for my CommunityControllerSpec!!!
Another thought. As I am working in a TDD Style, I always write the spec first and when I add a new method to a class, Autotest first fails with:
Which is fair enough
This was done on purpose.
March 5th, 2008 at 2:07 am
Great tip! I’ve wished for this functionality for months!
March 5th, 2008 at 2:07 am
@Neil – the ‘-f’ option makes it so autotest does not run everything until you change something. As soon as you make a change it does its normal thing: as soon as you get red followed by green, it’s going to run the whole suite. I want to make it so it runs a subset of the suite to keep things moving faster.
March 5th, 2008 at 2:07 am
Good codes. So far i have no bugs with them.
March 5th, 2008 at 2:07 am
@David,
March 5th, 2008 at 2:07 am
@David,
March 5th, 2008 at 2:07 am
@Neil – I don’t find that funny
March 5th, 2008 at 2:07 am
I’ve been having the same experience as Niel – when going from red to green it doesn’t run the entire suite anymore.
March 5th, 2008 at 2:07 am
David said: @Jean-Michel – the “one file” thing is only cases in which I’m working on something very focused that has no incoming dependencies yet. So I’d fire up autotest, restricting it to the one file (or one spec and one implementation file), and get that working right, and then restart autotest with the full suite (or just the directories for the encompassing component).
Now I understand better your needs and your tip . I can’t live without Autotest either
As for execute_latest_failure – seems like that would have to be re-written all the time, as it names a specific example. Or am I missing something?
Jean-Michel replies: Yes. In fact, I was a bit ashamed of my hack. This is the full code:
def execute_latest_failure """-e 'CommunityController (when the session has been resetted) AJAX add_country should not throw exception'"
end
So every time, I need Autotest to execute the “ONE” spec I am working on, I commment the first line of execute_latest_failure and uncomment the second line … Pathetic I know
Sorry about the misunderstanding. I meant: as I write the spec before the code, it’s normal that the spec failed with “NoMethodError”. When I save my spec, it triggers Autotest and the spec fails. Then, I will add the new method in the class …
I think autotest is the wrong place for adding code to your code. That should be in the editor, in my opinion. This is the sort of help java developers get from tools like eclipse and IntelliJ out of the box that could make a Ruby developer’s life a bit easier, but putting it in autotest makes autotest a bit too invasive IMO.
At the end of the day, you’re right, this is definitely a feature that IDEs should provide.
What is your background?
March 5th, 2008 at 2:07 am
@Jean-Michel – yes, I too come from the wonderful world of java tools and I do long for the day that my language of choice has the same level of TDD/Refactoring support. It’s moving along. NetBeans has some cool features now (including code completion for RSpec!) but it’s got a way to go.
March 5th, 2008 at 2:07 am
David,
# my horrible hack order = order.select do |k,v| (ENV['AUTOTEST'] and ! ENV['AUTOTEST'].empty?) ? Regexp.new(ENV['AUTOTEST']).match(k) : true end.uniqZenSpider seems to hate the idea of scoping autotest, so I doubt we’ll ever get this functionality built in. I don’ think there’s a hook you can use for this anymore, at least I didn’t see anything there in the code that looks promising.
March 5th, 2008 at 2:07 am
David,
# my horrible hack order = order.select do |k,v| (ENV['AUTOTEST'] and ! ENV['AUTOTEST'].empty?) ? Regexp.new(ENV['AUTOTEST']).match(k) : true end.uniqZenSpider seems to hate the idea of scoping autotest, so I doubt we’ll ever get this functionality built in. I don’ think there’s a hook you can use for this anymore, at least I didn’t see anything there in the code that looks promising.
March 5th, 2008 at 2:07 am
PS How can I get that little cloud before the comment link on the blog? Is that Haloscan and Blog template?;
March 5th, 2008 at 2:07 am
@chris – what gives you the idea that ZenSpider hates the idea of scoping autotest? He actually invited me to submit a patch for this before I realized it was just as easy to do it .autotest as described above
March 5th, 2008 at 2:07 am
help a noob—where is the .autotest file (on Mac OS X)
March 5th, 2008 at 2:07 am
David – you may be right.
If it’s not, you can create it.