Archive

Posts Tagged ‘autotest’

Autospec with custom directory/file names

January 17th, 2010 Sean DeNigris No comments

Autotest is a great time-saver when doing BDD (or TDD for the less-enlightened, lol).  Autospec seemlessly integrates Rspec.  However, if you don’t use the expected “spec/*_spec.rb” structure, autotest will not find your specs – or examples, as I call them.

It is very easy to use whatever structure you want using the following steps:

Telling Autotest to use Rspec as the test runner

The first thing you want to happen is for Autotest to use Rspec as the test runner.  This usually happens automatically using autospec, which tests for the presence of the spec directory.  Since we do not want a spec directory, we must tell explicitly tell Autotest to do this.  So:

Step 1: in your project directory create a file autotest/discover.rb with the following line:

Autotest.add_discovery { "rspec" }

Teaching Autotest about our custom directory structure

In order to do this, we have two options.  If we want to use the same structure for all our projects, we can put a file in our home directory, otherwise we can add custom files to each project directory.

Step 2: create a file .autotest with the following code:


class Autotest::Rspec < Autotest remove_method :consolidate_failures def consolidate_failures(failed) filters = new_hash_of_arrays failed.each do |spec, trace| if trace =~ /\n(\.\/)?(.*example\.rb):[\d]+:/ filters[$2] << spec end end return filters end remove_method :add_options_if_present def add_options_if_present # :nodoc: File.exist?("examples/spec.opts") ? "-O examples/spec.opts " : "" end end Autotest.add_hook(:initialize) {|at| %w{.git .svn .hg .swp .DS_Store ._* tmp}.each do |exception| at.add_exception(exception) end at.clear_mappings # take out the default (test/test*rb) at.add_mapping(%r%^(examples|third_party)/.*_example.rb$%) { |filename, _| filename } at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m| ["examples/#{m[1]}_example.rb"] } at.add_mapping(%r%^examples/(example_helper|shared/.*)\.rb$%) { at.files_matching %r%^(examples|third_party)/.*_example\.rb$% } #nil }

Let’s take it piece by piece:


def consolidate_failures(failed)
  filters = new_hash_of_arrays
  failed.each do |spec, trace|
    if trace =~ /\n(\.\/)?(.*example\.rb):[\d]+:/
      filters[$2] << spec
    end
  end
  return filters
end

This method tells Autotest which test files have failed by pulling the file names out of the test output. Since autospec looks for *_spec.rb files, it will not find our custom files. I use *_example.rb filenames, so you should replace that part of the regex with whatever you use.


def add_options_if_present # :nodoc:
    File.exist?("examples/spec.opts") ? "-O examples/spec.opts " : ""
  end

This method tells Rspec where to find an option file. Again, replace the details with whatever you use.

In Autotest.add_hook(:initialize):

  %w{.git .svn .hg .swp .DS_Store ._* tmp}.each do |exception|
    at.add_exception(exception)
  end

This tells Autotest to ignore certain files that are irrelevent to testing

at.clear_mappings

This tells Autotest not to use any other mappings i.e. the default test/test*rb, or Rspec’s spec/*_spec.rb

at.add_mapping(%r%^(examples|third_party)/.*_example.rb$%) { |filename, _|
  filename
}
at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
  ["examples/#{m[1]}_example.rb"]
}
at.add_mapping(%r%^examples/(example_helper|shared/.*)\.rb$%) {
  at.files_matching %r%^(examples|third_party)/.*_example\.rb$%
}

This is the meat of the customization. It tells Autospec, based on which files have changed, which tests to run. Replace my regexes with your custom matches.

The end

Once you have added both these files, running autospec from your project directory will work as it should!