Forum: RSpec [Cucumber] Tables

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-21 18:40
(Received via mailing list)
Being the author of Cucumber, some of you might be surprised that I ask
this
question:

How should I go about to implement a Cucumber feature and step
definition
with the following data?
http://gist.github.com/99220 (just look at the first file for now)

Imagine I'm opening a restaurant where customers are asked for their
religion. Based on what they answer, they will be presented with a
tailored
menu. (Apologies in advance if I'm ignorant about what different people
it).

In Cucumber, there are several ways to put this table in a feature. It
can
be part of a table in a Scenario Outline's Examples section (
http://wiki.github.com/aslakhellesoy/cucumber/scen...), or it
can
be sent to a Step as a multiline argument (
http://wiki.github.com/aslakhellesoy/cucumber/mult...).

In either case, I'm not happy about the feature and step definitions I
end
up with. The Scenario Outline version has annoying duplication. I have
to
duplicate each meat 3 times! This makes it hard to read and edit. The
multiline step argument version isn't much better. If a menu for a
religion
is wrong I'll only get one error, the error won't tell me what's wrong
(unless I explicitly craft my error messages in the step definition) and
max
one failure will show (there is only one scenario).

There should be a better way to express this kind of tests. But I'm not
sure
how. Is there a smarter way with the current Cucumber? If not, how would
you
*like* to express this sort of problem?

Cheers,
Aslak
3c28deaff162aeda44f2e0bcdca1dacf?d=identicon&s=25 Joseph Wilk (josephwilk)
on 2009-04-21 19:59
(Received via mailing list)
aslak hellesoy wrote:
> different people it).
> edit. The multiline step argument version isn't much better. If a menu
> for a religion is wrong I'll only get one error, the error won't tell
> me what's wrong (unless I explicitly craft my error messages in the
> step definition) and max one failure will show (there is only one
> scenario).
>
> There should be a better way to express this kind of tests. But I'm
> not sure how. Is there a smarter way with the current Cucumber? If
> not, how would you *like* to express this sort of problem?

I think the second way is a better way of expressing the problem, the
output/run strategy is the problem.

What you really want is an examples table that is embedded in a step
(different from a step table, maybe by keyword?) that causes the step to
be run multiple times for each of the values. So rather than using
placeholders we embedded a Examples table in the step.

Just my inital thoughts. I'll knock together an example and more ideas
when I get home...

--
Joseph Wilk
http://blog.josephwilk.net
Cdf378de2284d8acf137122e541caa28?d=identicon&s=25 Matt Wynne (mattwynne)
on 2009-04-21 20:18
(Received via mailing list)
On 21 Apr 2009, at 17:39, aslak hellesoy wrote:

> different people it).
> much better. If a menu for a religion is wrong I'll only get one
> error, the error won't tell me what's wrong (unless I explicitly
> craft my error messages in the step definition) and max one failure
> will show (there is only one scenario).
>
> There should be a better way to express this kind of tests. But I'm
> not sure how. Is there a smarter way with the current Cucumber? If
> not, how would you *like* to express this sort of problem?
>
> Cheers,
> Aslak

Looking at the forks of your example gist, I think I would have done
it exactly the way mabes suggested. I'm not sure if I can think of a
better way.

Matt Wynne
http://blog.mattwynne.net
http://www.songkick.com
Eb2a56fa7dcb166e12f92faad72ad074?d=identicon&s=25 Aaron VonderHaar (Guest)
on 2009-04-21 20:19
(Received via mailing list)
I think the scenario outline is the way to go, but in your example
it's not clear to me what the behavior is supposed to be-- is the
expected output in your Then statement really providing value?

Here's my take on it:  http://gist.github.com/99281

Scenario Outline: Religious menus
   Given the customer is "<Religion>"
   When he asks for the menu
   Then he should see pork selections if <Pork>
   And he should see lamb selections if <Lamb>
   And he should see veal selections if <Veal>

Scenarios:
   | Religion  | Pork | Lamb | Veal |
   | Christian |    Y |    Y |    Y |
   | Jewish    |      |    Y |    Y |
   | Muslim    |      |    Y |    Y |
   | Hindu     |      |    Y |      |

Cheers,
--Aaron V.
387fb00ef9d6d523d43018d9c81ab36b?d=identicon&s=25 Jonathan Linowes (Guest)
on 2009-04-21 20:52
(Received via mailing list)
Without adding a new feature to Cucumber, I'd probably do

Scenario Outline: Religious menus
   Given the customer is a "<Religion>"
   When they ask for the menu
   Then they should be presented with "<Meats>"

Examples:
   | Religion  | Meats             |
   | Christian |  Pork, Lamb, Veal |
   | Jewish    |        Lamb, Veal |
   | Muslim    |        Lamb, Veal |
   | Hindu     |        Lamb       |

and then parse the meat string in the step definition

meat.split(',') etc
387fb00ef9d6d523d43018d9c81ab36b?d=identicon&s=25 Jonathan Linowes (Guest)
on 2009-04-21 20:57
(Received via mailing list)
On Apr 21, 2009, at 1:57 PM, Joseph Wilk wrote:

> What you really want is an examples table that is embedded in a
> step (different from a step table, maybe by keyword?) that causes
> the step to be run multiple times for each of the values. So rather
> than using placeholders we embedded a Examples table in the step.


like this?
https://rspec.lighthouseapp.com/projects/16211/tic...
3c28deaff162aeda44f2e0bcdca1dacf?d=identicon&s=25 Joseph Wilk (josephwilk)
on 2009-04-21 22:24
(Received via mailing list)
On Tue, Apr 21, 2009 at 7:32 PM, Jonathan Linowes
<jonathan@parkerhill.com> wrote:
>
> On Apr 21, 2009, at 1:57 PM, Joseph Wilk wrote:
>
>> What you really want is an examples table that is embedded in a step
>> (different from a step table, maybe by keyword?) that causes the step to be
>> run multiple times for each of the values. So rather than using placeholders
>> we embedded a Examples table in the step.
>
>
> like this?

Not quite, I was thinking of running the whole scenario for the
examples step table rather than just the step.

However I really like Ben's suggestion of a sub-table
(http://gist.github.com/99255).

I think it would be conceptually easier for a non-technical user to
grasp than my first suggestion which makes it a big win for me.

--
Joseph Wilk
http://blog.josephwilk.net
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-21 23:15
(Received via mailing list)
On Tue, Apr 21, 2009 at 10:20 PM, Joseph Wilk <joe@josephwilk.net>
wrote:

> >> we embedded a Examples table in the step.
> I think it would be conceptually easier for a non-technical user to
> grasp than my first suggestion which makes it a big win for me.
>

Thanks a lot for all the suggestions so far. I like Ben's subtable too.
In the example: "I should be presented a menu with <Meat Options>" I
assume
the step definition would be:

Then /I should be presented a menu with/ do |meat_hash|
  # meat_hash has the following value the 2nd time (Jewish):
  {'Pork'=>'N', 'Lamb'=>'Y', 'Veal'=>'Y'}
end

However, having the <Meat Options> as part of the step would be
inconsistent
with how the regexp matching is currently working.

Here is an alternative: http://gist.github.com/99376

The idea is that we add a new kind of multiline argument in addition to
pystrings and tables: Hash. This is
done using the familiar <> delimiters as a multiline argument. What's
inside
it has no significance other than documentation.
The keys of the hash would be the same as the Examples table header
*minus*
the columns that are referred in other steps.

In essence it achieves the same as Ben's, but relying on a convention
(removing referenced columns) rather than introducing
a new, more complex table markup.

WDYT?

Aslak
Cdf378de2284d8acf137122e541caa28?d=identicon&s=25 Matt Wynne (mattwynne)
on 2009-04-21 23:18
(Received via mailing list)
On 21 Apr 2009, at 22:13, aslak hellesoy wrote:

> step
> examples step table rather than just the step.
> assume the step definition would be:
>
>
> WDYT?

I like.

I also like that it's called a 'meat hash'. Sounds tasty :)

Matt Wynne
http://beta.songkick.com
http://blog.mattwynne.net
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-21 23:35
(Received via mailing list)
On Tue, Apr 21, 2009 at 8:50 PM, Jonathan Linowes
<jonathan@parkerhill.com>wrote:

>   | Jewish    |        Lamb, Veal |
>   | Muslim    |        Lamb, Veal |
>   | Hindu     |        Lamb       |
>

This certainly would work, but what if we're not dealing with booleans
(Lamb/No Lamb), but numbers?
|34,76,89| doesn't read so well...

Aslak
C694a032be7518a0d704318895f8fe1d?d=identicon&s=25 Ben Mabey (mabes)
on 2009-04-22 00:22
(Received via mailing list)
aslak hellesoy wrote:
>     >> What you really want is an examples table that is embedded in a
>     Not quite, I was thinking of running the whole scenario for the
> In the example: "I should be presented a menu with <Meat Options>" I
> Here is an alternative: http://gist.github.com/99376
> a new, more complex table markup.
>
> WDYT?

Interesting.. so your meat_hash was derived from the columns of the
table that were not used previously in the scenario?  Meaning, that is
why Religion was not part of your meat_hash.

That makes sense, and.. since the scenario outline is parsed before any
of the examples are ran through that convention could be maintained no
matter what order the delimiters appear in the scenario. (Just thinking
out loud here...)

Yeah,  I like it. I also agree with Matt about meat_hash.  All this
meat_hash talk is making me hungry...

However, what if people wanted multiple hashes?  Subtables would allow
for this but a single hash solution would not.  FWIW, here is a very
contrived exampled:

http://gist.github.com/99424

I agree that the sub-table is probably adding too much complexity,
especially since we have a simpler alternative and no real use cases for
it yet.  Basically, you can ignore that last gist, I was just
experimenting with contrived use cases. :)


-Ben
5bcb339d586a103797bf05323b61d6c5?d=identicon&s=25 Nigel Thorne (Guest)
on 2009-04-22 00:49
(Received via mailing list)
I would prefer it to be explicit what columns I am using, that way if
you
have two steps that require this technique in your scenario it still
works.Relying
on an implicit 'the rest' doesn't work in that situation.
In my scenario I would like to have something like this..

Given I am logged in as <Role>
And I have a Protocol <Initial Protocol Details>
When I clone the protocol
Then the new protocol will contain <Cloned Protocol Details>

Examples:
*| Role | Initial Protocol Details   ||| Cloned Protocol Details
|||
*|      | Name  | Urgent | Description | Name   | Urgent | Description
|
 | Admin| Prot1 | Y      | Protocol 1  | Prot~1 |  Y     | Clone of
Protocol 1 |
 | Admin| Prot1 | N      | Protocol 1  | Prot~1 |  N     | Clone of
Protocol 1 |
etc.


Here I am using ||| to signify the number of columns that are included
in
the above grouping. Not sure how best to indicate which rows are header
rows.

WDYT?


2009/4/22 Ben Mabey <ben@benmabey.com>
5bcb339d586a103797bf05323b61d6c5?d=identicon&s=25 Nigel Thorne (Guest)
on 2009-04-22 00:52
(Received via mailing list)
Here is the same thing as a gist http://gist.github.com/99443
2009/4/22 Nigel Thorne <rspec@nigelthorne.com>
387fb00ef9d6d523d43018d9c81ab36b?d=identicon&s=25 Jonathan Linowes (Guest)
on 2009-04-22 02:29
(Received via mailing list)
no offense to anyone here but all this is starting to remind me of
the days of green ASCII terminals... there's a reason gui's, wysiwyg
editors and typographic fonts were invented...
ok, nevermind, back to plain text, proportional font, character chart
art ....
:)
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-22 06:04
(Received via mailing list)
On Tue, Apr 21, 2009 at 11:39 AM, aslak hellesoy
<aslak.hellesoy@gmail.com> wrote:
> Being the author of Cucumber, some of you might be surprised that I ask this
> question:
>
> How should I go about to implement a Cucumber feature and step definition
> with the following data?
> http://gist.github.com/99220 (just look at the first file for now)

You left out:

| Vegetarian   |    N |    N |    N |

>
> *like* to express this sort of problem?
How about something like this:

http://gist.github.com/99235

That doesn't require a new construct and I *think* it solves the
problem (obviously I haven't run it).

An alternative would be to add a new rule or construct in which the
step definition can drive things a bit more. Something like
http://gist.github.com/99244 where the fact that the step def accepts
3 block args would let it consume the next three columns in the table.
Not sure how crazy that would be - just an idea.

WDYT?
387fb00ef9d6d523d43018d9c81ab36b?d=identicon&s=25 Jonathan Linowes (Guest)
on 2009-04-22 06:06
(Received via mailing list)
the output would be weird, eg

>   Then he should see pork selections if
>   And he should see lamb selections if Y
>   And he should see veal selections if
>
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-22 08:02
(Received via mailing list)
On Wed, Apr 22, 2009 at 2:27 AM, Jonathan Linowes
<jonathan@parkerhill.com>wrote:

> no offense to anyone here but all this is starting to remind me of the days
> of green ASCII terminals... there's a reason gui's, wysiwyg editors and
> typographic fonts were invented...ok, nevermind, back to plain text,
> proportional font, character chart art ....
> :)
>

Text is king. It's always possible to build GUIs on top of text. And
that
will happen with Cucumber. One of FIT's biggest flaw (IMO) is that it
doesn't have an underlying format below HTML (too high level).

Ok - let's not derail the table discussion in this thread.
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-22 08:16
(Received via mailing list)
On Tue, Apr 21, 2009 at 6:56 PM, David Chelimsky
<dchelimsky@gmail.com>wrote:

> You left out:
> > In Cucumber, there are several ways to put this table in a feature. It
> > up with. The Scenario Outline version has annoying duplication. I have to
> > how. Is there a smarter way with the current Cucumber? If not, how would
> you
> > *like* to express this sort of problem?
>
> How about something like this:
>
> http://gist.github.com/99235
>

This is actually one of the best I've seen so far. However it doesn't
scale
for multiple columns. (Imagine if you have 5 of them - they easily get
mixed
up, or you make a spelling mistake).

I have also taken the meat+hamburge example and tweaked a little bit:
http://gist.github.com/99620
As you can see I'm a little sceptical of complex tables. Instead I have
invented the Range for feature writers. You specify a range of columns
you
want for a column hash. (This could work along with my example where you
don't specify a range, just any token, and get the "rest").


> That doesn't require a new construct and I *think* it solves the
> problem (obviously I haven't run it).
>
> An alternative would be to add a new rule or construct in which the
> step definition can drive things a bit more. Something like
> http://gist.github.com/99244 where the fact that the step def accepts
> 3 block args would let it consume the next three columns in the table.
> Not sure how crazy that would be - just an idea.
>

That's an interesting idea, but would't this introduce a positional
dependency that could make it hard to detect mistakes? I'll have to
think
more about it.

I love this discussion! More! More!

Aslak
3f37c31a4f7c9ae3743b4464dbbd4652?d=identicon&s=25 John Goodsen (Guest)
on 2009-04-22 17:42
(Received via mailing list)
I definitely prefer the range solution over the others.
C6ce9a98479a04c47d143d444ae317c6?d=identicon&s=25 Kero van Gelder (Guest)
on 2009-04-22 19:25
(Received via mailing list)
> >   | Jewish    |        Lamb, Veal |
> >   | Muslim    |        Lamb, Veal |
> >   | Hindu     |        Lamb       |
>
> This certainly would work, but what if we're not dealing with booleans
> (Lamb/No Lamb), but numbers?
> |34,76,89| doesn't read so well...

Actually, I did just that, together with a colleague.
(I removed info about what the algorithm actually computes, but
the +/- indicates a threshold for that algorithm is/is not crossed;
there are four algorithms not two; sorry about all that editing)

  Scenario Outline: measuring a series of daily weights
    Given patient Lara
    When she measures her weight as <weights> kg
    Then ROT algorithm result should be <ROT>
    And MACD algorithm result should be <MACD>
    ...

    Examples:
      | weights                      | ROT | MACD | ...
      |  71   72.5 72   73.3 73.6    |  +  |  -   |
      |  71   72   73   74   75      |  -  |  +   |
      ...

I find this readable enough (it is much more readable than the long
series of scenarios we had before).

The numbers are a sequence as input for the algorithm.
The sequences are concrete examples to show the differences between the
outcomes of the four algorithms.

What strikes me in your meat examples, is that there is a mapping
from religion to types of meat that can be served (or dishes, in the
end).
You can test that the mapping works, why are you trying to be
exhaustive in your examples?

Bye,
Kero.
942a74b1b71ca62234ae690b44699ebc?d=identicon&s=25 unknown (Guest)
on 2009-04-22 21:25
(Received via mailing list)
________________________________
From: aslak hellesoy <aslak.hellesoy@gmail.com>

> Here is an alternative: http://gist.github.com/99376


I'm a fan of simple, which means I'm a fan of this.  The only thing I
can think of that would be simpler is this:

 * When the arity of the matcher is larger by one than the matched step
provides, pass the hash from the current scenario in that slot (barf if
there's no table or scenario-table to fill that arg).

 * Also, don't remove any values from the hash based on
already-used-ness (no important reason to have it, leaves things more
flexible for the developer, and is also simpler.  Win!).

I see one downside here: the implicitness.  That could be solved by one
of:

* The extra <meats> line from the gist above.  With the implicitness it
has, it feels like a wash to me.  I've added something that introduces
extra questions instead of just being understood.

* Convention, or even formal syntax like "... from the scenario" (i.e.,
if you're implicitly expecting the scenario row to go into the matcher,
say so in the G/W/T line).

* You could have a 'strict' or 'warnings' setting (hi, I coded in Perl
for 15 years) or the opposite, a "I've done what I intended, just run
'em" setting, to help ensure the user gets what she wants (with respect
to the arity mismatch).

I think it's clear, I lean toward the convention of saying "... from the
scenario table" or something example-specific: "The menu should have the
correct meat offerings".  I don't think the 'strict' mode is needed.

Nobody's going to question that the step definition will have the
necessary information available to it - they might question how it gets
there (Cuke internal implementation) or how they get at it (adding the
extra arg to the |arg,list,*hash*|).  But I think it's sufficiently
intuitive when all things are considered.

If you like this, please send the two cents to... oh, never mind :)

Randy
5bcb339d586a103797bf05323b61d6c5?d=identicon&s=25 Nigel Thorne (Guest)
on 2009-04-23 00:41
(Received via mailing list)
My initial approach to this (when I hit it in my work) was to get around
this problem by catching the whole row from the example in the
Before(scenario) filter, putting it into a well known member @data, so
all
steps have access to it.
The problem with this is that it is then implicit which fields are used
by
each step, not explicit. This leaves me feeling sad as it looses some of
it's power as documentation.

It also means you can't use the same step from an  outline in a normal
scenario. (but I don't see a way around this with any of the solutions..
except "given ... <Pork> <Lamb> <Beef>")

Nigel

2009/4/23 <r_j_h_box-sf@yahoo.com>
C694a032be7518a0d704318895f8fe1d?d=identicon&s=25 Ben Mabey (mabes)
on 2009-04-23 02:10
(Received via mailing list)
John Goodsen wrote:
> I definitely prefer the range solution over the others.
I agree, it makes sense and is simple IMO.
This topic is locked and can not be replied to.