[rspec-users] Step matchers

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


On 10/15/07, Zach Dennis <zach.dennis at gmail.com> wrote:
> 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"
>   end
>
> 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)
>     # ...
>   end
>
>
> > 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
> over.
>
> >
> > > 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
> margin.
>
> 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|
>
>    end
>

What are your thoughts about using symbol identifiers rather then
question marks? I think this increases readability and gets rid of
ambiguity at least for me.

step "a user named :username" do |username|
   ....
end

-- 
Zach Dennis
http://www.continuousthinking.com


More information about the rspec-users mailing list