[rspec-users] Step matchers

Wincent Colaiuta win at wincent.com
Mon Oct 15 10:43:10 EDT 2007

El 15/10/2007, a las 14:21, "David Chelimsky" <dchelimsky at gmail.com>  

> On 10/15/07, Wincent Colaiuta <win at wincent.com> wrote:
>> - The customer/client (not necessarily with any programming
>> knowledge) writes the stories in a format which is (almost) plain  
>> text.
> Why almost? Because there is required syntax? We're asking them to be
> able to write this:
> Story: employee accrues 1 day per month
>  As an employee
>  I want to accrue 1 day per month during my first year
>  So that I can replenish my self
>  Scenario: accrual after one month
>    Given an employee
>    When employee has worked 1 month
>    Then employee should accrue 1 day vacation time
>  Scenario: accrual after 2 months
>    Given an employee
>    When employee has worked 2 months
>    Then employee should accrue 1 days vacation time

And as far as requirements go the leading whitespace could be treated  
as totally optional (because you can rest assured that people will  
get it wrong, use tabs instead of spaces, or spaces instead of tabs,  
or mix them up etc).

>> - The developer then writes custom "step matchers"; where do they go?
> TBD. Probably in a directory under stories named steps or  
> step_matchers.

My main concern here is that you're now having to keep two files in  
sync to have the stories work properly. The great thing about the  
Story Runner in its current form (and RSpec too) is that you can  
start off by writing a skeleton using a natural-language-like Ruby  
DSL, and then you flesh it out with code to fulfill its purpose. In  
other words, turn on code folding and a non-programmer can read it  
out loud and know what it means; turn off code folding and a  
programmer can see what's happening inside. It's great because your  
spec files are both readable by all and executable by the computer!

But if your stories are stored in separate files, you no longer have  
that. If you edit the story you have to regenerate the story's  
specification in a way that preserves existing changes. Discrepancies  
between the files will break the stories. And on top of this you have  
to worry about a third place, the place where you define your step  
matchers (unless you define them in your "implementation" file, but  
you're still having to worry about two files then). So I am a little  
worried about this becoming very cumbersome and error-prone compared  
to the rest of RSpec.

If I understand the proposals correctly then this will be great for  
non-programmer customers, but for programmers it will actually be  
awkward and uncomfortable, which would be a shame because one of  
RSpec's great selling points is that it makes TDD/BDD pleasant.

I can't help but thinking that the best solution will be of the form:

Story "..." do
   Scenario "..." do
     Given "..." do; end
     And "..." do; end
     When "..." do; end
     Then "..." do; end

Where, whatever the format ends up being, the customer knows that the  
user-editable bits are the ones between the quotes, and the bits  
between "do" and "end" are for the programmer. I thought the proposal  
to have "strings like $this one" wasn't bad.

> There are some pieces missing. Pat's initial description (the
> beginning of this thread) recognizes Steps, but I'd like to see them
> include the mechanics. Something like this:
>   matcher = StepMatcher.new("/^(.*) navigates to (.*)$") do
>     login_as arg1
>     get arg2
>   end
> Then the runner would translate this:
>   When admin navigates to the user list
> to this:
>   find_when('admin navigates to the user list')
> which would find the matcher defined above and eventually do this:
>   matcher.run_step 'admin navigates to the user list'
> at which point 'admin' and 'the user list' would be extracted and
> thrown at the block.
> Obviously there are pieces missing here, but I think that this could
> prove very easy to use.

I'd rather see:

matcher = StepMatcher.new "$user navigates to $path" do |args|
   login_as args[0]
   get args[1]

Where StepMatcher can easily translate:

   "$user navigates to $path"

into a regex like:

   /\A([^ ])+ navigates to ([^ ]+)\z/

But I'd be even happier if this weren't stored in a separate file and  
were just part of the story file:

   When "$user navigates to $path" do |args|
     login_as args[0]
     get args[1]

Thanks for taking the time to explain all this, David!

(And on a side note: I recently switched to the digest version of the  
mailing list, so I am aware that these replies aren't showing up as  
continuations of existing threads... sorry about that! Does anyone  
know of a way to avoid this when replying to the digest?)


More information about the rspec-users mailing list