[rspec-users] Reuse of Cucumber Features

Zach Dennis zach.dennis at gmail.com
Thu Apr 9 12:47:09 EDT 2009


On Thu, Apr 9, 2009 at 9:29 AM, Williams, Wesley
<Wesley.Williams at sabre.com> wrote:
> Matt,
>
> Hmm, I think this is one way to do it.  I will need to get my customer
> to think differently about defining the requirements.  They really like
> the tables.

Some times table just work best. I love writing scenarios with natural
language, but I've hit many cases where the inputs and outputs are
best displayed as a table, and it's easier for the customer to gr0k,
then to read a short novel.

This kind of re-use that you seem to need sounds like a potential
feature for Cucumber. A way to utilize an external file to house a
table of data. e.g.:

Background
   Given I have the following set of flights:
      | foo | bar | baz |
      ...

Would become

 Background
    Given I have the following set of flights:
    FromFile: flights/scheduleA

And then you'd have the flights/scheduleA house:

      | foo | bar | baz |
      ...

Cucumber could dump in the table data it found from the file, and
print it out when running the scenarios, and it allows some sets of
sample data be re-used easily, in an understandable manner.

WDYT?

>
> Thanks,
> Wes
>
> -----Original Message-----
> From: rspec-users-bounces at rubyforge.org
> [mailto:rspec-users-bounces at rubyforge.org] On Behalf Of Matt Wynne
> Sent: Thursday, April 09, 2009 9:58 AM
> To: rspec-users
> Subject: Re: [rspec-users] Reuse of Cucumber Features
>
> On 8 Apr 2009, at 10:31, Williams, Wesley wrote:
>
>> All,
>>
>> I know this is an older post but I have a similar but different set
>> of scenarios I need to handle.  I have a set of flight related
>> scheduling features, such as delay, reschedule, and cancel, each
>> with multiple scenarios that have an effect on later flights in the
>> schedule (there are a lot of scenarios actually).  What (I think J)
>> I need is a set of flights that I can reuse, in a Background: given
>> section, by all of these features and scenarios, that is defined in
>> a way that is reusable and visible in each of the feature definitions.
>>
>> Is this possible?  Is there a better way to do this?
>>
>> Example:
>>
>> Feature: Delay flights with down line adjustments
>>   As a flight scheduler
>>   I want to delay a flight and have the down line flights adjusted
>> for different periods
>>   So I can more quickly update a schedule when events happen
>>
>>     Background:
>>       Given I have the following flights scheduled:
>>         |aircraft | flight number | dept date | dept time |
>>         | XX1      |  XX0001              | 03Mar2009 |  1000        |
>>         | XX1      |  XX0002              | 03Mar2009 |  1400        |
>>         | XX1      |  XX0003              | 03Mar2009 |  2100        |
>>         | XX1      |  XX0004              | 04Mar2009 | 1000         |
>>
>>    Scenario:  delay flights with down line adjustments for same dept
>> date as delayed flight
>>       When I delay flight XX001 by 5 mins
>>       Then XX001 departs at 1005
>>       Then XX002 departs at 1405
>>       Then XX003 departs at 2105
>>       Then XX004 departs at 1000
>>
>> OR
>>
>>    Scenario:  delay flights with down line adjustments for same dept
>> date as delayed flight
>>       When I delay flight XX001 by 5 mins
>>       Then the scheduled flight should be
>>         |aircraft | flight number | dept date | dept time |
>>         | XX1      |  XX0001              | 03Mar2009 |  1005        |
>>         | XX1      |  XX0002              | 03Mar2009 |  1405        |
>>         | XX1      |  XX0003              | 03Mar2009 |  2105        |
>>         | XX1      |  XX0004              | 04Mar2009 | 1000         |
>>
>> There are many more scenarios.
>>
>> Is there a nice way to removed the duplication that is here,
>> especially since I will need a similar set of flights for other
>> scheduling change scenarios?  Does anyone see a nice way to simplify
>> the scenarios?
>>
>> Great tool by the way.
>>
>> Thanks,
>> Wes
>
> Have you seen this?
>
> http://www.benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-i
> n-user-stories/
>
> Another way to remove duplication (and noise) from Cucumber steps is
> the hide the details in the Ruby code that implements the step, and
> write a much more general step in the feature file like this:
>
>        Given there are 3 flights departing on the same day
>        And the flights all leave at different times
>        And there is another flight leaving on the following day
>        When the earliest flight is delayed by 5 mins
>        Then the flights on the first day should all be delayed by 5
> minutes
>        And the flight on the second day should be unaffected
>
> These kind of steps can be clearer to read, but the trade-off is that
> your underlying step code gets more complex as you start writing logic
> to deliver these specific scenarios. Still, if you're clever about it,
> these 'declarative' steps can still be pretty re-usable.
>
> HTH,
> Matt
>
>>
>> Subject: [rspec-users] Reuse of Cucumber Features
>>
>> +lots :)
>>
>> Generally when we have problems with features its because we are
>> trying to
>> do to much at once. So in your case date entry is being complicated by
>> different contexts, birth and incident. One of the tennents of BDD
>> is to
>> write the simplest thing you can to make you feature pass. I think
>> another
>> one should be "first of all write the simplest scenarios". So taking
>> one of
>> your examples
>>
>> Scenario: Enter Valid Incident
>>   When I fill incident correctly
>>   I should recieve a confirmation
>>
>> Then your incident step can be something like
>>
>> When /^I fill incident correctly$/ do
>>   fill_in("incident[name]", :with => ...
>>   ...
>> end
>>
>> If you wanted to specify validation in features you could do a step
>> like
>>
>> When /^I fill incident correctly except$/ do |field|
>>   When "I fill in incident correctly"
>>   fill_in("incident[#{field}]", :with => ''
>> end
>>
>> now you can create new features like
>>
>>  Scenario: Enter Valid Incident with no date
>>   When I fill incident correctly except date
>>   I should recieve an error
>>
>> With a bit more trickery you could have
>>
>>   When I fill incident correctly except date which is xxx
>>
>> Taking this approach you can build incrementally quite complex
>> validation
>> features whilst stll keeping each scenario simple and focused on one
>> thing.
>> Whether you should do this with features or put this detail
>> somewhere else
>> is another question entirely.
>>
>> On another point with dates have you considered international
>> issues. All
>> the dates you've given in your example are valid (technically) there
>> just
>> not in the format you prefer.  Also consider that the invalidity of
>> dates
>> might be context dependant e.g. an incident date in the future, an
>> appointment in the past.
>>
>> HTH
>>
>> Andrew
>>
>>
>> 2008/12/14 Pat Maddox <pergesu at gmail.com>
>>
>> > Hi Steve,
>> >
>> > I likely would only write two scenarios, one for a valid date and
>> one
>> > for an invalid one.  Then I would write object-level specs to
>> determine
>> > what a valid date is.  Extract this to a validator that you can
>> reuse
>> > throughout your model.
>> >
>> > If it's important that you write features for each potential invalid
>> > date format (because you want to communicate them with the customer)
>> > then I would write a feature file similar to what you show...but it
>> > would be focused only on the date, I wouldn't mention patients or
>> > incidents at all.  Date entry seems to be an important concept in
>> your
>> > application, so I would write one feature that specifies how I
>> expect
>> > date entry to work, and then I can just write valid/invalid dates
>> for
>> > patient and incident features.  Same idea as the first paragraph,
>> but
>> > using features instead of specs.
>> >
>> > Pat
>> >
>> >
>> > "Steve Molitor" <stevemolitor at gmail.com> writes:
>> >
>> > > Thanks -- that gets me closer.  Here's an example.  Let's say I
>> have two
>> > features, 'Create new patient' and 'Create new incident'.  To
>> > > create a new patient you have to enter a valid birth date.  To
>> create a
>> > new patient you must enter a valid birth date.  To create a new
>> > > incident you must enter a valid incident date.  The rules for
>> date entry
>> > are the same:
>> > >
>> > > Feature:  Date entry
>> > >
>> > >   Scenario: Invalid month
>> > >   When I fill in the date value with "13/01/2000"
>> > >   I should see "Invalid date..."
>> > >
>> > >   Scenario: Invalid year (not 4 digits)
>> > >   When I fill in the date value with "13/01/00"
>> > >   I should see "Invalid date..."
>> > >
>> > >   Scenario: Separate with slashes (ok)
>> > >   When I fill in the date value with "01/13/2000"
>> > >   I should see "valid date..."
>> > >
>> > >   Scenario: Separate with dashes (ok)
>> > >   When I fill in the date value with "01-13-2000"
>> > >   I should see "valid date..."
>> > >
>> > >   .... etc....
>> > >
>> > > Given the above, how should I write the 'create new patient' and
>> 'create
>> > new incident' features?  I don't want to copy and paste all the
>> > > date related scenarios, but I do want to specify (and test) that
>> the
>> > patient birth date and incident date fields conform to the general
>> date
>> > > rules.  Here's how the 'create new patient' and 'create new
>> incident'
>> > features would look with some copy and pasting:
>> > >
>> > > Feature: Create new Patient
>> > >
>> > > Scenario:  Enter invalid birth date
>> > >   Given I fill in "birth date" with "13/01/2000"
>> > >   And I fill in "patient name" with "Sam Smith"
>> > >   When I press "Save"
>> > >   I should see "Invalid birth date '13/01/2000'"
>> > >
>> > > Scenario:  Enter valid birth date, valid name
>> > >   Given I fill in "birth date" with "01/13/2000"
>> > >   And I fill in "patient name" with "Sam Smith"
>> > >   When I press "Save"
>> > >   I should see "Patient Created Successfully"
>> > >
>> > > Scenario:  Enter valid birth date with dashses.....
>> > > -------
>> > >
>> > > Feature: Create new Incident
>> > >
>> > > Scenario:  Enter invalid incident date
>> > >   Given I fill in "incident" with "13/01/2000"
>> > >   And I fill in "supervisor" with "Sam Smith"
>> > >   When I press "Save"
>> > >   I should see "Invalid incident date '13/01/2000'"
>> > >
>> > > Scenario:  Enter valid incident date, valid supervisor
>> > >   Given I fill in "incident date" with "01/13/2000"
>> > >   And I fill in "supervisor" with "Sam Smith"
>> > >   When I press "Save"
>> > >   I should see "Incident Created Successfully"
>> > >
>> > > Scenario:  Enter valid incident date with dashes....
>> > > -----
>> > >
>> > > Am I making sense?  I want to specify the date in the features,
>> as there
>> > may be extra requirements like birth dates can not be in the future
>> > > in addition to the generic date requirements.  And I want to
>> validate
>> > that the form checks for valid dates, displays the appropriate error
>> > > message when invalid, and uses the common rules for parsing.
>> But I don't
>> > want to copy and paste those scenarios in every feature.  I think
>> > > reusing steps as you mention is probably the solution but I'm
>> stuck on
>> > how to word it and put it together in my case.
>> > >
>> > > Steve
>> > >
>> > > On Sun, Dec 14, 2008 at 8:41 AM, Matt Wynne <matt at
>> mattwynne.net> wrote:
>> > >
>> > >     On 13 Dec 2008, at 20:58, Steve Molitor wrote:
>> > >
>> > >         What's the best way to handle a requirement that shows
>> up as a
>> > sub-requirement requirement in other features?  For example let's
>> say
>> > >         users can enter dates in various forms throughout my
>> application.
>> >   There is one set of global rules specifying the formats in which
>> > >         dates may be entered, and how they are interpreted.  I
>> put that
>> > in one feature.  In various other features, like 'Create new
>> > >         patient', one can enter dates, like the patient's birth
>> date.  I
>> > want to do something like 'and the date entry shall follow the
>> > >         normal rules' but I'm not sure how to do that in an
>> example
>> > driven way, without copying and pasting from other features.
>> > >
>> > >         Does my question make sense?  Any suggestions?
>> > >
>> > >     Do you know that you can call steps within steps?
>> > >
> http://blog.mattwynne.net/2008/11/14/dry-up-your-cucumber-steps/
>> > >
>> > >     Is that what you're looking for?
>> > >
>> > >     Matt Wynne
>> > >     http://blog.mattwynne.net
>> > >     http://www.songkick.com
>> > >
>> > >     _______________________________________________
>> > >     rspec-users mailing list
>> > >     rspec-users at rubyforge.org
>> > >     http://rubyforge.org/mailman/listinfo/rspec-users
>> > >
>> > > _______________________________________________
>> > > rspec-users mailing list
>> > > rspec-users at rubyforge.org
>> > > http://rubyforge.org/mailman/listinfo/rspec-users
>> > _______________________________________________
>> > rspec-users mailing list
>> > rspec-users at rubyforge.org
>> > http://rubyforge.org/mailman/listinfo/rspec-users
>> >
>>
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
>
> Matt Wynne
> http://blog.mattwynne.net
> http://www.songkick.com
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>



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


More information about the rspec-users mailing list