[rspec-users] Step matchers

Zach Dennis zach.dennis at gmail.com
Mon Oct 15 21:18:47 EDT 2007

On 10/15/07, Pat Maddox <pergesu at gmail.com> wrote:
> On 10/15/07, Zach Dennis <zach.dennis at gmail.com> wrote:
> > To me adding a story parser to parse a text file adds overhead to the
> > rspec team and to developers and customers using it. In a way I fear
> > that the textual freedom of a raw text file will lead to many gray
> > area's both on the rspec's implementation of it and also for
> > developers trying to explaining to their customers why or why they
> > cannot do something. I don't know if this is greater then the
> > conversation that already has to take place though. I personally don't
> > know customer's who write the final draft of an acceptance test.
> The parser will be trivial.  You're looking at 60 lines tops.
> > Wincet Colaitua brings up a good point [3] in regards to StepMatchers:
> >
> >   "My main concern here is that you're now having to keep two files in
> >   sync to have the stories work properly."
> Perhaps there was some confusion with how I implemented that initial
> StepMatcher.  I've since explained that ultimately it should contain
> both the matching and mechanics.  Unless Wincent was referring to
> keeping the plain-text stories in sync with the StepMatchers.  On the
> surface that sounds valid, but at the same time if you've got
> Given "a user named", "Wincent" do |name|
>   @user = User.create :name => name
> end
> .... some other scenario
> Given "a user named", "Pat"
> You still have to keep stuff in sync.  It's easy here of course
> because it's all in the same file...but then what happens when you
> recognize you're using this "a user named" step in every single one of
> your stories?  You extract it to another file, and then now you have
> to make sure the story steps are in sync with the extracted steps.
> > Wincent also brings up in the same post [3]
> >
> >  "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"
> >
> > This is the part of Story Runner that I want to hold onto. In my
> > opinion a worthwhile balance to start exploring is one that does the
> > following things:
> >
> > * creates an easy one to one mapping between a description and a method
> > * remove do/end blocks, they are not needed and are a negative for the customer
> > * keeps story's clean and tidy, not full of unnecessary code artifacts
> >
> > An implementation of this is the test/unit StoryRunner project that
> > I've been working on.
> >   http://continuous.rubyforge.org/svn/trunk/test_unit_story_runner/
> >
> > It is similar to rspec's implementation but it does the three things
> > listed above. A nicely color formatted example can be found at
> > http://pastie.caboo.se/107537
> >
> > A few things to note about the example:
> >
> > * Story's do not use do/end blocks to organize scenarios. It is not
> > needed. Scenario's belong to the last Story declaration preceding it.
> >
> > * Scenario's do use do/end blocks to nest their story parts.
> >
> > * Descriptions used for Given, Then, When and And translate to a
> > method call. The rules are simple. Take the description, downcase it
> > and strip out punctuation. Replace whitespace with underscores and try
> > to find a method. If one exists, call it. If one doesn't exist strip
> > the first word, and try again. Repeat until there are no words left.
> > If no method was matched then raise an exception with the original
> > description string.
> See, I would much rather mentally map
> Given a user named Wincent to
> StepMatcher.new("a user named ?")
> than to
> def a_user_named___(name)
> It seems to me that mapping to a method leaves you with the sync
> issues but in a far less readable format.

I don't like:
  def a_user_named___(name)

I prefer:
  def a_user_named_wincent
     @user = a_user_named "Wincent"

IMO arguments for helper method arguments should be used carefully. I
don't think things that simply identify should be used as arguments. I
would rather use things that affect the outcome or behavior of what I
am trying to test. For example:

  Given "a user named Wincent"
  When "he makes a guess of", 200_000

  def make_a_guess_of(guess)
    # ...

> Another thought is that if
> you have a full-fledged object, you can do basic things like
> decomposing methods.

Are you relating this to StepMatchers or another concept? I see
StepMatchers as a way to decompose based on a string pattern, not
necessarily method names.

> > The idea behind this is that you create a clean way to write and
> > maintain Story's. It minimizes the "cody" aspects while still allowing
> > you to write executable ruby code.
> The main point I'm trying to get across, and I believe Dave is (obv
> jump in if I'm wrong), is that once we start making these sorts of
> enhancements then there's no reason to make it Ruby executable code
> anymore.  If we don't need do...end blocks, and we don't need
> arguments, there's really nothing left and the Ruby interpreter is no
> longer adding any value and should be refactored away.

Syntax highlighting is a very nice value to be added for a developer.
Although it is a secondary citizen to what is trying to be achieved.
Right now I'm teetering on the fence of this. Is any value lost to the
developer worth the value picked up by the customer is the argument I
am trying to consider. I don't have an answer yet. Still mulling it

> > The helper methods which are implemented follow a simple convention
> > for translating a  sentence description into a helper method and the
> > implementation of the story's are implemented in well named helper
> > methods (which i think adds to maintainability over StepMatchers).
> How does auto-mapping to method names add to maintainability over
> auto-mapping to strings?  I'm not seeing that, and I'd like to
> understand your perspective.

I am worried about maintainability as the list of possible arguments
grow. One argument is pretty straight forward.
   StepMatcher.new("a user named ?")   # username

It's common to find permutations of story part descriptions and based
on where those ? are it could become cumbersome to track down:
   StepMatcher.new("a ? named ?") # account type, name

This and others like it could make it difficult to track down
StepMatchers. The lack of place holders allowed in method names makes
it an easier mapping then StepMatchers, even if is only by a small

I'm not against StepMatchers, just trying to determine if the value
they add outweighs the burden they add. I do like think of step
matchers in the syntax of:

   step "a user named ?" do |username|


Zach Dennis

More information about the rspec-users mailing list