[rspec-users] Step matchers

Pat Maddox pergesu at gmail.com
Sun Oct 14 23:49:06 EDT 2007


On 10/14/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> On 10/14/07, Pat Maddox <pergesu at gmail.com> wrote:
> > On 10/14/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> > > On 10/14/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> > > > On 10/14/07, Pat Maddox <pergesu at gmail.com> wrote:
> > > > > I think we all know that the readability of steps isn't great right
> > > > > now, and in fact there's a very recent thread that discusses just
> > > > > that.  It was that recent thread that prompted me to explore this a
> > > > > bit.
> > > > >
> > > > > The basic idea is that you define step matchers, which have a regex,
> > > > > and then you match step names against that regex.  Kind of tough for
> > > > > me to explain so I'll just link to some code :)
> > > > >
> > > > > spec: http://pastie.caboo.se/107116
> > > > > impl: http://pastie.caboo.se/107117
> > > > >
> > > > > Instead of writing
> > > > > Given "a user named __ who is __ years old", "Pat Maddox", 22
> > > > >
> > > > > it allows you to write
> > > > > Given "a user named Pat Maddox who is 22 years old"
> > > > >
> > > > > I wrote it out as a separate matcher because it was just easiest to do
> > > > > it that way while I explored this approach, no messing around with
> > > > > RSpec internals to get it to really work.  However if we went this
> > > > > route the structure would certainly be different.
> > > > >
> > > > > Hopefully you can get the idea from the example code.  Ideally what I
> > > > > would like is to write step libraries that are external to the stories
> > > > > themselves.  The stories would be much clearer because the
> > > > > implementation would not be embedded, and the step names themselves
> > > > > would make a lot more sense.
> > > > >
> > > > > wdyt?
> > > >
> > > > LOL - I just suggested something like this in the other thread you
> > > > cite. Though your idea strikes me as far more flexible and usable.
> > > > Well done!!!!
> > >
> > > This just occurs to me. If we do away with the need for special
> > > characters/positioning, blocks, etc, we should be able to do just
> > > this, no?
> > >
> > > Given a savings account with 100 dollars
> > > When the account owner asks for 101 dollars
> > > Then the account owner should receive 0 dollars
> > > Then the account should have 100 dollars
> > >
> > > Look mom - no quotes!
> >
> > How would you plan to implement this?  Read in a text file, strip the
> > leading Given/When/Then and match each line?
> >
> > The one catch I see is that because stories are structured, you still
> > need something to demarcate steps within a scenario and scenarios
> > within a story.
> >
> > In general, I prefer your syntax, making it look like a plain-text
> > spec instead of Ruby code.  I question whether it's a big enough win
> > to justify writing a parser instead of simply writing valid Ruby.  At
> > this point, personally I'd say no, but I can see how it would be nice
> > for customers and spec readers/maintainers.
> >
> > Actually, would you mind showing an example of a full spec with this
> > syntax?  Maybe something like:
> >
> > Story: Creating a post
> >   As a user
> >   I want post to my blog
> >   So that I can share information with my fellow Rubyists
> >
> >   Scenario: anonymous user
> >     Given no blog posts in the system
> >
> >     When I POST to /posts with title=Post Title, body=Post body
> >
> >     Then the page should show Post title
> >     And the page should show Post body
> >     And the page should show Posted by: 'anonymous'
> >
> >   Scenario: logged in user
> >     Given no blog posts in the system
> >     And a user named Pat
> >     And logged in as Pat
> >
> >     When I POST to /posts with title=Custom Title, body=Custom body
> >     And the page should show Custom Title
> >     And the page should show Custom body
> >     And the page should show Posted by: 'Pat'
>
> At a high level, this is exactly what I came up with:
>
> 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
>
> The Story: and Scenario: indicators are quite clear. This should be a
> no-brainer to parse.
>
> I think the real potential pitfalls in this approach have to do with
> StepMatchers that have similar expressions and the user writes a step
> with a one-word difference that invokes the wrong step and results in
> inaccurate feedback.
>
> That said, the ability for customers to be able to write
> stories/scenarios in plain text is the holy grail IMO. That is the
> promise of FIT. I've seen failure and success with FitNesse. The
> success required customers who were able to grok tables and wikis. It
> fell down when they didn't care about these things, or when they
> didn't understand how to structure things w/ correct setups,
> teardowns, etc.
>
> A lot remains to be seen, but I think this plain text approach will
> eliminate a LOT of that. Especially situations where deveoper-centric
> things like setup became part of the customer facing FitNesse pages.
> With the Story Runner, we'd be able to hide all of that out of the
> view of the customer. Great stuff!
>
> >
> > Actually a parser for this would be quite simple
>
> Dead simple. It would also allow us to do away with methods like
> Given, When and Then, which some people have objected to (because of
> the capitalization), because the stories are no longer expressed
> directly in Ruby. Internally, the parser could use a StepFactory to do
> things like create_given, create_when, etc (or however we decide to
> name these).
>
> I'm really excited about this idea!
>
> Cheers,
> David

I'm working with a customer who's got a decent-sized Rails app with
absolutely 0 lines of test code.  The first thing we'll be doing is
writing a bunch of user stories together.  I'm going to do it in this
new format, so I ought to have at least a basic implementation in a
couple of days as a matter of necessity :)

re: step matchers that are close - hopefully we can make the step
names brittle enough that it won't be too much of an issue.  If you
saw my test code, it uses a line begin and end anchor, and because
most of the regexp is exact text then it has to match pretty
precisely.  We'll see what happens with that.  Another idea I
mentioned earlier was that of "vocabularies" which would allow you to
import a step library into a story.  I can certainly envision writing
two steps that have similar, or even the same name, but that would
execute differently depending on context.  Sticking the steps in
different vocabularies would prevent clashes.

Pat


More information about the rspec-users mailing list