April 18, 2008

Ruby zentest autotest and Netbeans 6.1

In netbeans auto test feature works well with rails projects but fails with simple ruby projects.
ZenTest has very strange heuristics for non rails projects:

  • Test files must be stored in the test directory
  • Implementation files must be stored in the lib directory
  • Test files names must start with test_
  • Test class names must start with Test
  • Test files corresponding to a specific implementation file must be named test_<name of implementation file>.rb
Active* libraries and many others have different convention for naming test files and classes:
  • Test files must be stored in the test directory
  • Implementation files must be stored in the lib directory
  • Test files names must end with _test
  • Test class names must end with Test
  • Test files corresponding to a specific implementation file must be named <name of implementation file>_test.rb
Moreover netbeans use this convention to find testing file and test for specific file (rclick->navigate->go to test/go to tested file).

So if I have project with following layout:
lib
--example
----some_class.rb
test
--example
----some_class_test.rb

Autotest gives me:
Dunno! nbproject/private/rake-t.txt
Dunno! lib/example/some_class.rb
Dunno! README
Dunno! lib/main.rb
Dunno! Rakefile
Dunno! nbproject/project.xml
Dunno! nbproject/project.properties
Dunno! test/example/some_class_test.rb

So autotest simply doesn't work with this test naming convention by default.
Lucky for us ZenTest have hooks mechanism that allows to change default behavior.

So I wrote .autotest file and put it in project directory:
lib
--example
----some_class.rb
test
--example
----some_class_test.rb
.autotest

.autotest contents:

Autotest.add_hook :initialize do |at|
at.clear_mappings
at.add_mapping(/^lib\/(.*)\.rb$/) do |f, m|
at.files_matching(/^test\/#{m[1]}_test\.rb$/)
end

at.add_mapping(/^test\/(.*)_test\.rb$/) do |f, m|
at.files_matching(/^test\/#{m[1]}_test\.rb$/)
end
end

class Autotest

def path_to_classname(s)
sep = File::SEPARATOR
f = s.sub(/^test#{sep}((unit|functional|\
integration|views|\
controllers|helpers)\
#{sep})?/, '').sub(/\.rb$/, '').split(sep)
f = f.map { |path| path.split(/_/).map { |seg|
seg.capitalize }.join }
res = f.join('::')
res
end
end
Теперь это выглядит так:



So I edit any class and autotest it! It very cool feature to have. Thanks for zentest authors.
I hope this post will help anyone.

0 comments: