How to Write JUnit Test Sets in Rake

As DiffJ has been rewritten in JRuby, it now has numerous tests, with a group of tests in which each test corresponds to a add/delete/change type, such as methods being added to a class declaration.

I found myself wanting to run subsets of tests, such as all those for methods. The organization of the tests is that pathnames match the scope of the code being checked, so, for example, src/test/ruby/diffj/type/method/parameters/typechange/test.rb is the test for checking for a change in the type of parameters of a method, which is part of a type, meaning an interface or class. (As a parenthetical aside, the test files themselves match the test pathnames, so the two files being tested here are src/test/resources/diffj/type/method/parameters/typechange/d0/ and src/test/resources/diffj/type/method/parameters/typechange/d1/ And yes, this begs for an Emacs shortcut for toggling among the files, which I haven’t written yet.)

Although I’m a Rake novice, I had an idea of what I wanted: a way to specify in the Rakefile a subset of tests. Yes, I probably could have written test suites, but for whatever reason, it seemed more logical to do this as part of a build. And being a Z shell user, I also knew the pattern to apply. More about that in a minute.

So here’s what I wanted: to run “rake test:method”, and have that run all the unit tests under src/test/ruby/diffj/type/method. Or in glob-speak, “src/test/ruby/diffj/type/method/**/test*.rb”. (My testcases without their own tests are named “tc.rb”, so src/test/ruby/diffj/type/method/parameter/tc.rb has code common to the testcases under src/test/ruby/diffj/type/method/parameter.)

Enjoying the wonderful experience of writing object-oriented build scripts (bitterly said as a professional maintainer of Ant code), I subclassed the Rake test task,

class DiffJRakeTestTask < Rake::TestTask
  def initialize name, filter = name
    super(('test:' + name) => :testscompile) do |t|
      t.libs << $srcmainrubydir
      t.libs << $srctestrubydir
      t.pattern = "#{$srctestrubydir}/**/#{filter}/**/test*.rb"
      t.warning = true
      t.verbose = true
# ... and others

Going roughly line by line, that takes a parameter such as “method”, creates a test task named “test:method”, and adds a glob for test files (“test*.rb”) under a directory matching the filter, which defaults to the name. The “lib” lines add the directories containing my Ruby source and test code.

Using the filter means we can also specify partial or full paths for a test subset (even just a single file), writing them as needed, such as when working on failing tests. My needed ones ended up being the following:'method/body/zeroone')'method/parameters/zeroone')'method/throws/zeroone')'method/parameters/reorder')'method/parameters/reorder/typechange')

And we also can use the “filter isn’t the same as the name” functionality with the “test:all” task:'all', '*')

Yes, that’s probably redundant with the default “tests” task, but I prefer the feeling of wielding more control.

It looks like I’ll have DiffJ fully implemented in JRuby by the end of the month. I’m only packaging it as Zip files, and would appreciate offers to repackage it for Ubuntu, Fedora and other distributions. I know nearly nothing about Eclipse, but have had received interest in DiffJ as an Eclipse plugin, so that is another valuable contribution someone could make.