limiting scope of autotest

March 4th, 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!

Advanced Rails Recipes

January 4th, 2008

I’m pleased to announce that my contribution to Mike Clark’s new Advanced Rails Recipes book has been accepted and released. The book is available right now as a Beta PDF and includes dozens of delicious and nutritious recipes for enhancing your Rails applications and the process of developing them.

This is my first formal publication in the software world [1], and I couldn’t be more pleased than to have it be a Pragmatic Bookshelf [2] publication.

My recipe is entitled Describing Behaviour from the Outside-In With RSpec and it demonstrates the BDD approach to Rails apps starting with the view and working your way down to the controllers, models and database.

There is currently one other BDD recipe: Getting Started with BDD, which uses shoulda. There are also recipes for cooking up mocks, code coverage and html validity. And that’s just the testing related recipes.

There are also dozens of recipes dealing with UI, search, email, console, REST, db enhancements and even more general design improvements.

Like the first Rails Recipes book, this one is a must-have for any serious Rails developer who wants to take it up a notch in creating great web applications with Rails.


[1] My first publication of any kind was back around 1980 when I was a young professional magician. The book is called, simply, Coin Magic, and is a must have for any serious coin magician who wants to take it up a notch (see a trend here?) in presenting awesome feats of magic with ordinary coins. Back then I went by my first and middle name, David Arthur.

[2] The Pragmatic Programmers are also publishing my upcoming book with co-author Aslak Hellesøy, tentatively entitled Behaviour Driven Development in Ruby with RSpec.

RSpec 1.1

December 13th, 2007

The RSpec Development Team is pleased as glug (that’s kind of like punch, but more festive) to announce RSpec-1.1.0.

Thanks to all who have contributed patches over the last few months. Big thanks to Dan North and Brian Takita for their important work on this release. Dan contributed his rbehave framework which is now the Story Runner. Brian patiently did a TON of refactoring around interoperability with Test::Unit, and the result is a much cleaner RSpec core, and a clean adapter model that gets loaded when Test::Unit is on the path.

RSpec 1.1 brings four significant changes for RSpec users:

  • The RSpec Story Runner
  • Nested Example Groups
  • Support for Rails 2.0.1
  • Test::Unit interoperability

Story Runner

The RSpec Story Runner is Dan North’s rbehave framework merged into RSpec. The Story Runner is a framework for expressing high level requirements in the form of executable User Stories with Scenarios that represent Customer Acceptance Tests.

RSpec 1.1 also ships with a Ruby on Rails extension called RailsStory, which lets you write executable user stories for your rails apps as well.

Nested Example Groups

Now you can nest groups to organize things a bit better:


describe RubyDeveloper do

  before(:each) do
    @ruby_developer = RubyDeveloper.new
  end

  describe "using RSpec 1.1.0" do

    before(:each) do
      @ruby_developer.use_rspec('1.1.0')
    end

    it "should be able to nest example groups" do
      @ruby_developer.should be_able_to_nest_example_groups
    end

  end

  describe "using RSpec 1.0.1" do

    before(:each) do
      @ruby_developer.use_rspec('1.0.8')
    end

    it "should not be able to nest example groups" do
      @ruby_developer.should_not be_able_to_nest_example_groups
    end

  end

end

Running this outputs:

RubyDeveloper using RSpec 1.1.0
- should be able to nest example groups

RubyDeveloper using RSpec 1.0.8
- should not be able to nest example groups

== Support for Rails 2.0.1

gem install rails
rails myapp
ruby script/plugin install http://rspec.rubyforge.org/svn/tags/REL_1_1_0/rspec
ruby script/plugin install http://rspec.rubyforge.org/svn/tags/REL_1_1_0/rspec_on_rails
script/generate rspec

Test::Unit Interoperability

Contrary to popular belief, Spec::Rails, RSpec’s Ruby on Rails plugin, has been a Test::Unit wrapper since the the 0.7 release in November of 2006. RSpec 1.1 ups the ante though, offering a smooth transition from Test::Unit to RSpec with or without Rails:

1. Start with a TestCase:


require 'test/unit'

class TransitionTest < Test::Unit::TestCase
  def test_should_be_smooth
    transition = Transition.new(
      :from => "Test::Unit::TestCase",
      :to => "Spec::ExampleGroup" 
    )
    assert_equal "really smooth", transition.in_practice
  end
end

2. Require ‘spec’


require 'test/unit'
require 'spec'

class TransitionTest < Test::Unit::TestCase
  def test_should_be_smooth
    transition = Transition.new(
      :from => "Test::Unit::TestCase",
      :to => "Spec::ExampleGroup" 
    )
    assert_equal "really smooth", transition.in_practice
  end
end

3. Convert TestCase to ExampleGroup


require 'test/unit'
require 'spec'

describe "transitioning from TestCase to ExampleGroup" do
  def test_should_be_smooth
    transition = Transition.new(
      :from => "Test::Unit::TestCase",
      :to => "Spec::ExampleGroup" 
    )
    assert_equal "really smooth", transition.in_practice
  end
end

4. Convert test methods to examples


require 'test/unit'
require 'spec'

describe "transitioning from TestCase to ExampleGroup" do
  it "should be smooth" do
    transition = Transition.new(
      :from => "Test::Unit::TestCase",
      :to => "Spec::ExampleGroup" 
    )
    assert_equal "really smooth", transition.in_practice
  end
end

5. Convert assertions to expectations


require 'test/unit'
require 'spec'

describe "transitioning from TestCase to ExampleGroup" do
  it "should be smooth" do
    transition = Transition.new(
      :from => "Test::Unit::TestCase",
      :to => "Spec::ExampleGroup")
    transition.in_practice.should == "really smooth" 
  end
end

6. Un-require test/unit


require 'spec'

describe "transitioning from TestCase to ExampleGroup" do
  it "should be smooth" do
    transition = Transition.new(
      :from => "Test::Unit::TestCase",
      :to => "Spec::ExampleGroup" 
    )
    transition.in_practice.should == "really smooth" 
  end
end

At every one of these steps after step 2, you can run the file with the ruby command and you’ll be getting RSpec’s developer friendly output. This means that you can transition things as gradually as you like: no wholesale changes.

That’s the story. Thanks again to all who contributed and to all who continue do so.

RubyConf 2007 Talk

December 7th, 2007

The RSpec/BDD talk that Dave Astels and I presented at RubyConf 2007 has been posted for your viewing pleasure.

There are also a bunch of other RubyConf talks posted on the same site.

One correction: In our talk, I said that the role/feature/reason story format came from Mike Cohn’s book User Stories Applied. The real source was a project team at Connextra that Tim MacKinnon was a part of. Tim later joined Thoughtworks, where Dan North learned about it from Tim.

I did, in fact, learn about it from Mike Cohn, but it was at a talk he did at an Agile Conference a couple of summers back. I had also read his book, and somewhere in my head merged the talk and the book.

Nested Example Groups

November 28th, 2007

Since rspec first appeared on the scene, users have been asking for nested example groups. Well it has finally arrived. RSpec 1.1.0 will ship with support for nesting, so you’ll be able to do things like this:


describe RSpec do
  before(:each) do
    @rspec = RSpec.new
  end

  describe "at release 1.0.8" do
    before(:each) do
      @rspec.version = "1.0.8" 
    end

    it "should not support nested example groups" do
      @rspec.should_not support_nested_example_groups
    end
  end

  describe "at release 1.1.0" do
    before(:each) do
      @rspec.version = "1.1.0" 
    end

    it "should support nested example groups" do
      @rspec.should support_nested_example_groups
    end
  end
end

This will output:

RSpec at release 1.0.8
- should not support nested example groups

RSpec at release 1.1.0
- should support nested example groups

If you’re using trunk, you can do this now with revision 3009 or later.

Happy nesting!

before_action/after_action

November 6th, 2007

A while back there was either a feature request in the rspec tracker, or a suggestion on one of the rspec mailing lists, for a feature to DRY up controller specs.

Read the rest of this entry

RubyConf slides

November 5th, 2007

Here are the slides from the presentation that Dave Astels and I did at RubyConf 07.

Plain Text Stories: Part III

October 24th, 2007

Here’s the latest update to Plain Text Stories. Effective r2789 in RSpec’s trunk.

Step 1: Write a Story

Story: simple addition

  As an accountant
  I want to add numbers
  So that I can count beans

  Scenario: add one plus one
    Given an addend of 1
    And an addend of 1

    When the addends are added

    Then the sum should be 2
    And the corks should be popped

  Scenario: add two plus five
    Given an addend of 2
    And an addend of 5

    When the addends are added

    Then the sum should be 7

Step 2: Create Steps

# This creates steps for :addition
steps_for(:addition) do
  Given("an addend of $addend") do |addend|
    @adder ||= Adder.new
    @adder << addend.to_i
  end
end

# This appends to them
steps_for(:addition) do
  When("the addends are added")  { @sum = @adder.sum }
  Then("the sum should be $sum") { |sum| @sum.should == sum.to_i }
end

Step 3: Let her open the box … no, that’s not it …

Step 3: Run the Story with the steps you want (adding any that are only for this story as you go).

with_steps_for :addition do
  Then("the corks should be popped") {}
  run 'path/to/story/file'
end

Working with Rails?

with_steps_for :navigation do
  run 'path/to/story/file', :type => RailsStory
end

What about multiple groups of steps?


with_steps_for :login, :navigation, :form_submissions do
  run 'path/to/story/file'
end

Coming soon to a computer near you … (as soon as you can “seven up”)

Plain Text Stories on Rails

October 22nd, 2007

Since my last post on plain text stories, there have already been a few improvements, not the least of which is that it will now work with Rails. Again, this is trunk (rev 2769+) only and experimental.

Here’s a working example from an app that I’m working on:

stories/login
Story: registered user logs in
  As a registered user
  I want to have to log in
  So that only other registered users can see my data

  Scenario: user logs in and sees welcome page
    Given a user registered with login: foo and password: test
    When user logs in with login: foo and password: test
    Then user should see the welcome page

  Scenario: user logs in with wrong password
    Given a user registered with login: foo and password: test
    When user logs in with login: foo and password: wrong
    Then user should see the login form
    And page should include text: There was an error logging in.

  Scenario: user logs in with wrong login name
    Given a user registered with login: foo and password: test
    When user logs in with login: wrong and password: test
    Then user should see the login form
    And page should include text: There was an error logging in.

[Update: modified to use runner.steps instead of runner.step_matchers]

stories/login.rb
require File.join(File.dirname(__FILE__), *%w[helper])

run_story :type => RailsStory do |runner|
  runner.steps << LoginSteps.new
  runner.steps << NavigationSteps.new
  runner.load File.expand_path(__FILE__).gsub(".rb","")
end

Here’s what’s new in this example:

  • run_story is added to the main object so you don’t have to remember that silly path to the PlainTextStoryRunner which will undoutedbly change!
  • run_story accepts arguments, including an options hash, which it will pass to the constructor of the PlainTextStoryRunner (in this case, :type => RailsStory)
  • run_story yields the runner, which now supports a load method which you use to tell it where to find the plain text story file.
  • run_story … runs the story

Keep your eyes peeled for more updates in the coming days.

Story Runner in Plain English

October 21st, 2007

Houston, we have Plain Text!

I just committed a first stab at a Plain Text Story Runner. It’s in RSpec’s trunk and will be (in some form) part of the next release.

Big thanks to Pat Maddox for the StoryPartFactory (which is now called StoryMediator) and to all on the rspec-users list who contributed their ideas and thoughts to the discussion about plain text stories.

Keep in mind that this is brand new and very experimental. I do not recommend that you start converting all your projects to using this.

That said …

A bit of background

[Update: modified to use And for multiple Givens, Whens or Thens]

The initial implementation of Story Runner supported syntax like this (slightly modified from Dan North’s article introducing rbehave):

Story "transfer to cash account",
%(As a savings account holder
  I want to transfer money from my savings account
  So that I can get cash easily from an ATM) do

  Scenario "savings account is in credit" do
    Given "my savings account balance is", 100 do |balance|
      @savings_account = Account.new(balance)
    end
    And "my cash account balance is", 10 do |balance|
      @cash_account = Account.new(balance)
    end
    When "I transfer", 20 do |amount|
      @savings_account.transfer_to(@cash_account, amount)
    end
    Then "my savings account balance should be", 80 do |expected_amount|
      @savings_account.balance.should == expected_amount
    end
    And "my cash account balance should be", 30 do |expected_amount|
      @cash_account.balance.should == expected_amount
    end
  end

  Scenario "savings account is overdrawn" do
    Given "my savings account balance is", -20
    And "my cash account balance is", 10
    When "I transfer", 20
    Then "my savings account balance should be", -20
    And "my cash account balance should be", 10
  end
end

While this is a really cool start, there are a couple of problems. One is that we’re constrained in the way we phrase things. Because the arguments become part of the phrase, we have to structure each phrase so that the argument comes at the end.

The other problem, for me, is that the differing levels of abstraction in the two scenarios make it difficult to read.

Enter Blockless Steps and Parameterized Steps

The first step in resolving this problem was to decouple the expression of the story from the steps, which is accomplished with the use of Parameterized Steps. Here’s how the story above might look:

[Update: using StepGroup/define instead of StepMatchers/add]

steps = StepGroup.new do |define|
  define.given("my savings account balance is $balance") do |balance|
    @savings_account = Account.new(balance.to_f)
  end

  define.given("my cash account balance is $balance" do |balance|
    @cash_account = Account.new(balance.to_f)
  end

  define.when("I transfer $amount") do |amount|
    @savings_account.transfer_to(@cash_account, amount.to_f)
  end

  define.then("my savings account balance should be $expected_amount" do |expected_amount|
    @savings_account.balance.should == expected_amount.to_f
  end

  define.then("my cash account balance should be $expected_amount" do |expected_amount|
    @cash_account.balance.should == expected_amount.to_f
  end

end

Story "transfer to cash account",
  %(As a savings account holder
    I want to transfer money from my savings account
    So that I can get cash easily from an ATM),
    :steps => steps do

  Scenario "savings account is in credit" do
    Given "my savings account balance is 100" 
    And "my cash account balance is 10" 
    When "I transfer 20" 
    Then "my savings account balance should be 80" 
    And "my cash account balance should be 30" 
  end

  Scenario "savings account is overdrawn" do
    Given "my savings account balance is -20" 
    And "my cash account balance is 10" 
    When "I transfer 20" 
    Then "my savings account balance should be -20" 
    And "my cash account balance should be 10" 
  end
end

A bit nicer, yes? The steps coming first is a bit noisy, but that could be extracted to another file, or perhaps we can add a means of associating them with the Story after the Story has already been parsed so they can move below the Story.

That bit aside, look how much cleaner the Story reads now. And we can do a couple of additional things to make it even nicer. One thing you might notice is that the line about transfering (When “I transfer 20”) doesn’t specify which way the transfer goes. We can improve on that by enhancing that step:

steps = StepGroup.new do |define|
  ...

  define.when("I transfer $amount from $source to $target") do |amount, source, target|
    if source == 'cash' and target == 'savings'
      @savings_account.transfer_to(@cash_account, amount.to_f)
    elsif source == 'savings' and target == 'cash'
      @cash_account.transfer_to(@savings_account, amount.to_f)
    else
      raise "I don't know how to transfer from #{source} to #{target}" 
    end
  end

  ...

That lets us write the step as

When "I transfer 20 from savings to cash"

As you can see, this is a big step towards making stories more clear and flexible.

More on Steps

Another thing you may have noticed is that the Steps are grouped together somewhat arbitrarily. Thanks to a couple of handy convenience methods, you can easily build up libraries of these steps and make them as broad or as granular as you like. Perhaps we want the account steps available to many stories, but the transfer step only to this one. Here’s how you can handle that:

class AccountSteps < Spec::Story::StepGroup
  steps do |define|
    define.given("my savings account balance is $balance") do |balance|
      @savings_account = Account.new(balance.to_f)
    end

    define.given("my cash account balance is $balance" do |balance|
      @cash_account = Account.new(balance.to_f)
    end

    define.then("my savings account balance should be $expected_amount" do |expected_amount|
      @savings_account.balance.should == expected_amount.to_f
    end

    define.then("my cash account balance should be $expected_amount" do |expected_amount|
      @cash_account.balance.should == expected_amount.to_f
    end
  end
end

steps = AccountSteps.new do |define|
  define.when("I transfer $amount") do |amount|
    @savings_account.transfer_to(@cash_account, amount.to_f)
  end
end

Here we’ve created a subclass of StepGroup, instantiated one and defined an additional ‘when’ that will only be available to this instance.

Goodbye quotes!

Once we were able to get rid of the blocks, the quotes made no sense. So we’ve added support for true plain text stories. So now our example can read like this:

Story: transfer to cash account
  As a savings account holder
  I want to transfer money from my savings account
  So that I can get cash easily from an ATM

  Scenario: savings account is in credit
    Given my savings account balance is 100
    And my cash account balance is 10
    When I transfer 20
    Then my savings account balance should be 80
    And my cash account balance should be 30

  Scenario: savings account is overdrawn
    Given my savings account balance is -20
    And my cash account balance is 10
    When I transfer 20
    Then my savings account balance should be -20
    And my cash account balance should be 10

That gets stored in a plain text file and you can run it by running a ruby file that looks like this:

require 'spec'
require 'path/to/your/library/files'
require 'path/to/file/that/defines/account_steps.rb'

# assumes the other story file is named the same as this file minus ".rb" 
runner = Spec::Story::Runner::PlainTextStoryRunner.new(File.expand_path(__FILE__).gsub(".rb",""))
runner.steps << AccountSteps.new
runner.run

And that’s it! It’s that simple. This is still in its very early phases and I’m certain there will be enhancements as people gain experience with it.

If you want to check it out yourself, grab the trunk and do the following:

cd trunk/rspec
ruby examples/stories/calculator.rb
ruby examples/stories/addition.rb

The first example uses Ruby with blockless steps. The second example uses a plain text story stored in examples/stories/addition.

Also, with a couple of small tweaks we’ll be able to consume plain text from any source (not just a local file) and feed it into the PlainTextStoryRunner. This means that we’ll be able to do things like email scenarios to an app that consumes email and runs the scenario against the system and emails you back a report! Crazy, huh?

Lastly, just a reminder, this is only in trunk right now (as of rev 2764), so if you want to explore it you’ll have to get the trunk.

Enjoy!!!!!

Topfunky has just released the first of a 3 part PeepCode series on rspec entitled rSpec Basics. I’ve gone through it myself and I am impressed.

I would recommend this for anybody who is just getting started with rspec and rails. As its title suggests, it covers the basics: a bit of BDD philosophy, getting things set up, writing simple examples, all the way through describing models.

As for advanced users, I’d recommend this to those of you who are interested in a few helpful tips and tricks. There is some material on the textmate bundles and integrating with growl. In fact, the approach to validating models is simple and pragmatic, and one that I suspect will become the standard in time.

The only constructive criticism I’d offer is that the discussion of the philosophy of the rspec team doesn’t recognize the roots of our philosophy in Test Driven Development. It seems to present writing focused examples, getting them to fail first, etc, as our idea. It is not. Just ask google.

Regardless, it is very exciting to see the beginnings of quality educational material on rspec and BDD emerging. Keep your eyes open in this space. I suspect there is quite a bit more on the horizon.

The question of how test behaviour implemented in abstract classes came up on the RSpec list yesterday. This is something that comes up periodically, so I thought it worth posting about. Over the years I’ve seen and tried a few different approaches to dealing with this problem and I’ve come to an approach that feels right to me. It stems from two basic principles:

  • Abstract classes don’t have any behaviour
  • Only remove duplication that actually exists

Abstract classes don’t have any behaviour

Abstract classes are a structural tool that we can use to share implementation between concrete classes. Sometimes they actually represent abstract types, but all too often they’re misused as convenient placeholders for shared implementation. When that happens, their presence clouds meaning.

In statically typed languages like Java and C#, you can spot this misuse by looking at the types being referenced in method signatures. If no methods accept the abstract class, then it isn’t really functioning as an abstract type in your system.

This is a bit more subtle in Ruby because we don’t have an abstract class construct and we think in duck types instead of static or runtime types. Abstract classes are really more of a convention than a language feature.

Regardless, this rule of thumb steers me away from testing abstract classes directly.

Only remove duplication that actually exists

This is a general rule of thumb that I like to apply whether I’m dealing with examples or subject code. Only remove actual duplication. If you start with something general before you have anything specific, there is a tendency to make assumptions about what the duplication will be, and those assumptions are often misguided.

In terms of abstractions, this rule of thumb guides me to extract abstraction when I see duplication rather than imposing it up front.

Putting the two together

The question on the list was specifically about how to test methods that live in in Application in a Ruby on Rails app. For the uninitiated, Application is the base class for all controllers in an MVC framework. Ruby doesn’t support abstract classes, so you can actually initialize Application, but AFAIK the Rails framework never does.

Based on the two principles, and given that I write executable examples first, I start by describing the behaviour of a concrete controller, developing methods directly on that controller against those examples. When a new controller comes along that should have the same behaviour, I’ll often duplicate the examples and the behaviour first and then extract the duplication into shared examples and the Application controller. This way, if there are any differences at all in the expected behaviour (which there often are) it easier to figure out the exact bits that I want to extract.

Once I’ve got the abstraction in both the examples and code I can just plug them in to the third, fourth, etc examples.

Other schools of thought

There is a runtime cost to pay when you’re running the same examples for multiple subclasses of an abstract class. You could argue that this is wasteful because the same implementation is being tested multiple times, which flies in the face of the goal of fast running test suites. This argument might lead you to write tests directly for the abstract class.

I can’t really disagree with the performance cost, yet I still prefer to approach it as I do because I find it more clear and less brittle to be describing the behaviour of concrete types rather than the behaviour of abstract types (which doesn’t really exist).

We finally released RSpec-0.9 today. We had a little trouble w/ 0.9.0, so we skipped ahead to 0.9.1.

To get the gem:
gem install rspec
To install the Spec::Rails plugin:
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_0_9_1/rspec
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_0_9_1/rspec_on_rails

This release comprises myriad improvements and changes, some of which I’ve blogged about here, the rest of which you can read about on the rspec website.

Of special note is our growing list of contributors. It is very exciting to be involved with a project that has such an active user group filled with imaginative people who have contributed some of RSpec’s most exciting new features.

Thank you, thank you, thank you to all who participate whether it is through patches, feature requests, bug reports, or simply interacting on the mailing lists. You’ve all had an important impact on RSpec’s growth.

Autotest (part of ZenTest) now supports RSpec. This is fantastic news! For those of you who do not know about autotest, it is a program that runs in the background while you are writing your tests and code. Each time you make a change it automatically reruns your tests – and now your specs, too! This is a powerful addition to the TDD/BDD experience.

Recent releases of both tools overlapped a bit so there are changes in RSpec-0.9.1 that are not reflected yet in ZenTest. Also, while ZenTest-3.5.2 supports Spec::Rails, RSpec’s Ruby on Rails plugin, it does not support non-Rails Ruby projects.

I’ve submitted a patch to the ZenTest project which addresses both of these issues. Until the patch is applied, or the issues are addressed in some other way, you can apply it yourself to get autotest working with RSpec for Rails and other projects. These steps work on a mac. I assume that the commands are quite similar for Linux and Cygwin users.

  1. Go to http://rubyforge.org/frs/?group_id=419 and download ZenTest-3.5.2.tgz
  2. Unpack the tar and
    tar zxvf ZenTest-3.5.2.tgz
    cd ZenTest-3.5.2
    
  3. Get and install the patch
    curl -O http://blog.davidchelimsky.net/files/ZenTest-3.5.2-rspec.patch
    patch -p0 < ZenTest-3.5.2-rspec.patch
    
  4. Build and install the gem
    rake gem
    sudo gem install pkg/ZenTest-3.5.2.gem
    

Once you’ve built and installed the patched gem, you run autotest as normal. Stand in the root of your project and say:

autotest

If you have a spec directory at the root of your project, autotest will load up rspec_rails_autotest for Rails projects and rspec_autotest for everything else.

To quote Josh Knowles, Happy (Auto)Specing!

Here’s a nice little enhancement in Spec::Rails-0.9.

Up until now, controller examples required that the controller be named:

#the old way
context "Login Controller" do
  controller_name :login
  ...

You’ll still be able to do that, but you’ll also be able to do this:

describe LoginController do
  ...

... and Spec::Rails will assume that LoginController is what you want to use.

This works for your helper examples as well:

describe PeopleHelper do
  ...