Cucumber - Adding a step definition


#1

List,

Quick question about Cucumber/Gherkin.

I’m considering adding ‘With’ as a step definition to support scenarios
like:

Given a policy
With a PCF practice state
And a secondary risk

I’m fairly new to ruby - but I can’t quite get this one figured out.
I’ve tried adding

Cucumber.alias_steps ([‘With’])

To my features/support/env.rb file, but when I run cucumber, I still get
a Syntax error. It looks like my ‘with’ never gets added to the original
list.

Suggestions?

Tim H.
Senior Software Engineer
PICA Group
615-713-9956 :cell
timothyjhart :Y!
removed_email_address@domain.invalid :AIM


Disclaimer: This electronic message may contain information that is
Confidential or legally privileged. It is intended only for the use of
the individual(s) and entity named in the message. If you are not an
intended recipient of this message, please notify the sender immediately
and delete the material from your computer. Do not deliver, distribute
or copy this message and do not disclose its contents or take any action
in reliance on the information it contains.



#2

On Fri, Mar 13, 2009 at 10:28 PM, Tim H. removed_email_address@domain.invalid wrote:

I’m fairly new to ruby - but I can’t quite get this one figured out. I’ve
tried adding

Cucumber.alias_steps ([‘With’])

To my features/support/env.rb file, but when I run cucumber, I still get a
Syntax error. It looks like my ‘with’ never gets added to the original list.

Unfortunately, this only aliases the ruby methods (this will let you
call
With /some step/ do…end in a step definition ruby file.
In order to make the plain text parser recognise other words, a change
is
needed in languages.yml.

If you add a feature request in Lighthouse I’ll see if I can add it.

Cheers,
Aslak


#3

Den 14. mars. 2009 kl. 13.59 skrev Matt W. removed_email_address@domain.invalid:

If you add a feature request in Lighthouse I’ll see if I can add it.

I’m not sure if I like this - dependency between steps seems like a
dodgy road to go down.

When you’re in a step definition, how would you know what object the
‘With’ was referring to?

Good question Matt. Let’s clarify this first. Maybe there is a better
way to express this with the current language.

Aslak


#4

On 13 Mar 2009, at 21:47, aslak hellesoy wrote:

To my features/support/env.rb file, but when I run cucumber, I still
get a Syntax error. It looks like my ‘with’ never gets added to the
original list.

Unfortunately, this only aliases the ruby methods (this will let you
call With /some step/ do…end in a step definition ruby file.
In order to make the plain text parser recognise other words, a
change is needed in languages.yml.

If you add a feature request in Lighthouse I’ll see if I can add it.

I’m not sure if I like this - dependency between steps seems like a
dodgy road to go down.

When you’re in a step definition, how would you know what object the
‘With’ was referring to?

Matt W.
http://blog.mattwynne.net
http://www.songkick.com


#5

On Mar 14, 2009, at 8:49 AM, “Aslak Hellesøy”
removed_email_address@domain.invalid wrote:

wrote:

I’m not sure if I like this - dependency between steps seems like a
dodgy road to go down.

When you’re in a step definition, how would you know what object the
‘With’ was referring to?

Good question Matt. Let’s clarify this first. Maybe there is a better
way to express this with the current language.

As a test, I removed the ‘add alias’ line from my env.rb file, and
updated languages.yaml. I updated the line that read

and: And

To read

and: And|With

Then my step_definition file can have a step definition like

Given /a PCF Practice state/ do … end

Which I’d exactly what I was looking for.

My only concern I’d that I’d like to be able to add the ‘With’ to the
language through code instead of having to update the yaml file. That
way I have the option of varying the language for specific projects
without having to ‘polute’ the basic language globally. I assumed this
was what the ‘add_alias’ function would do for me in the first place.


Disclaimer: This electronic message may contain information that is
Confidential or legally privileged. It is intended only for the use of
the individual(s) and entity named in the message. If you are not an
intended recipient of this message, please notify the sender immediately
and delete the material from your computer. Do not deliver, distribute
or copy this message and do not disclose its contents or take any action
in reliance on the information it contains.



#6

On Sat, Mar 14, 2009 at 5:59 AM, Matt W. removed_email_address@domain.invalid wrote:

I’m not sure if I like this - dependency between steps seems like a dodgy
road to go down.

I’m wondering how you’d feel about a style I’ve adopted:

Scenario: Accepting a direct challenge, without leaving a comment
Given there is a challenge
And I am logged in
And I have been invited to that challenge
When I visit the challenge’s page
And I press “Accept”
Then I should go to my attempt detail page for the challenge
And I should see that I accepted the challenge
And I should not see “Attempt Challenge”

Clearly, there is dependency between steps - each has to know what
challenge they’re working on, for one thing. But I’ve found that it
reads better than the alternative

Given there is a challenge call ‘Reach from the Stars’ for ‘Halo 3’
And I am logged in as Mark
And Mark was invited to ‘Reach from the Stars’ for ‘Halo 3’ on
‘Sept 1, 2009’ by ‘Bill’
When I visit the challenge page for 'Reach from the Stars for ‘Halo
3’
And I press “Accept”
Then I should go to Mark’s attempt detail page for the challenge
‘Reach from the Stars’ for ‘Halo 3’
And I should see that ‘You accepted this challenge on Sept 1,
2009’ And I should not see “Attempt Challenge”

The first one reads more like a business-level story to me and the
second one reads more like a test.

Thoughts?

///ark


#7

Is the syntax you’re using a misreading of the wiki advice on
Feature-Coupled
Steps.

Why not have

“GIven a policy with a PCF practice state and seconday risk”

This is not a featured coupled step because PCF practice state and
secondary
risk are part of the Policies state and are not seperate. Seperating the
step as you have done does not reduce coupling. In fact all it does is
complicate the steps because a variable containing the policy has to now
be
in the 3 steps.

Perhaps the need for a with is a ‘smell’ suggesting that you are
seperating
a step that is intrinsically coupled. So with really shouldn’t be needed
at
all.

HTH

Andrew

2009/3/13 Tim H. removed_email_address@domain.invalid


#8

On 14 Mar 2009, at 15:50, Mark W. wrote:

Given there is a challenge
reads better than the alternative
And I should see that ‘You accepted this challenge on Sept 1,
2009’ And I should not see “Attempt Challenge”

The first one reads more like a business-level story to me and the
second one reads more like a test.

Totally agree with this, and I do it all the time. On my team we allow
ourselves to use the term ‘the Widget’ to mean Widget.first, but we’ll
always assert Widget.count.should == 1 when we do.

We also have a nifty little convention that allows us to talk about
‘the Widget “Foo”’ and ‘the Widget “Bar”’ because pretty much every
entity in our domain (or at least the ones we refer to like this in
our features) has a #name attribute.

Matt W.
http://blog.mattwynne.net
http://www.songkick.com


#9

On Sat, Mar 14, 2009 at 1:33 PM, Matt W. removed_email_address@domain.invalid wrote:

We also have a nifty little convention that allows us to talk about ‘the
Widget “Foo”’ and ‘the Widget “Bar”’ because pretty much every entity in our
domain (or at least the ones we refer to like this in our features) has a
#name attribute.

That sounds like a great way to avoid the instance variable.

///ark


#10

On Mar 14, 2009, at 3:38 PM, “Andrew P.”
<removed_email_address@domain.invalidmailto:removed_email_address@domain.invalid> wrote:

Is the syntax you’re using a misreading of the wiki advice on
Feature-Coupled Steps.

Why not have

“GIven a policy with a PCF practice state and seconday risk”

Because the work we are currently doing is going to involve several
hundred different variations of over a hundred different attributes of a
policy. I need to make sure that I’m able to reuse as many statements
describing that policy as I possibly can.

Another factor is that our SME is going to be heavily involved in
creating these scenarios. A few concessions toward regular English will
help a great deal.

This is not a featured coupled step because PCF practice state and
secondary risk are part of the Policies state and are not seperate.
Seperating the step as you have done does not reduce coupling. In fact
all it does is complicate the steps because a variable containing the
policy has to now be in the 3 steps.

Perhaps the need for a with is a ‘smell’ suggesting that you are
seperating a step that is intrinsically coupled. So with really
shouldn’t be needed at all.

HTH

Andrew

2009/3/13 Tim H.
<mailto:removed_email_address@domain.invalidremoved_email_address@domain.invalidmailto:removed_email_address@domain.invalid>
List,

Quick question about Cucumber/Gherkin.

I’m considering adding ‘With’ as a step definition to support scenarios
like:

Given a policy
With a PCF practice state
And a secondary risk

I’m fairly new to ruby - but I can’t quite get this one figured out.
I’ve tried adding

Cucumber.alias_steps ([‘With’])

To my features/support/env.rb file, but when I run cucumber, I still get
a Syntax error. It looks like my ‘with’ never gets added to the original
list.

Suggestions?

Tim H.
Senior Software Engineer
PICA Group
615-713-9956 :cell
timothyjhart :Y!
mailto:removed_email_address@domain.invalidremoved_email_address@domain.invalidmailto:removed_email_address@domain.invalid :AIM


Disclaimer: This electronic message may contain information that is
Confidential or legally privileged. It is intended only for the use of
the individual(s) and entity named in the message. If you are not an
intended recipient of this message, please notify the sender immediately
and delete the material from your computer. Do not deliver, distribute
or copy this message and do not disclose its contents or take any action
in reliance on the information it contains.



rspec-users mailing list
mailto:removed_email_address@domain.invalidremoved_email_address@domain.invalidmailto:removed_email_address@domain.invalid
http://rubyforge.org/mailman/listinfo/rspec-usershttp://rubyforge.org/mailman/listinfo/rspec-users


rspec-users mailing list
removed_email_address@domain.invalidmailto:removed_email_address@domain.invalid
http://rubyforge.org/mailman/listinfo/rspec-users


#11

That sounds like a great way to avoid the instance variable.

Why is a named record preferable to an instance variable? It seems
like the coupling between steps is the same, but the coupled state is
stored differently. Maybe that’s the point - stored differently.

I’ve been tempted to start scenario lines with “With” as well, to get
away from the combinatorial explosion of setup steps for complex
entities (think decorator pattern). I’ve used tables too, but mine
looked more like this:

Given a policy with:
| PCF practice state | secondary risk |
| yes | yes |

Is that nasty? It means we can use one step to set all possible
boolean attributes of a policy, but it doesn’t read so well.

“With …” would mean steps that were coupled to the “last mentioned
thing”. That seems like a different kind of coupling - there is only
one piece of state involved (the last thing) rather than a map of
named things. But it’s less explicit and implies that the “last thing”
needs to be updated by each step that mentions things.

Matt, going back to Mark’s example, it sounds like you lean towards
the latter (i.e. repeat 'Reach from the Stars for ‘Halo 3’ throughout
the scenario). Is that correct?

Josh


#12

On 14 Mar 2009, at 22:01, Tim H. wrote:

Because the work we are currently doing is going to involve several
hundred different variations of over a hundred different attributes
of a policy. I need to make sure that I’m able to reuse as many
statements describing that policy as I possibly can.

Have you thought about using Scenario Outlines to express these
several hundred variations in a tabular format?

That would enable you something like:

Given a policy with
When blah
Then

Examples:
| policy features | outcome |
| a PCF practice state and seconday risk | foo |

Just a thought.

Matt W.
http://blog.mattwynne.net
http://www.songkick.com


#13

On 15 Mar 2009, at 00:30, Josh C. wrote:

That sounds like a great way to avoid the instance variable.

Why is a named record preferable to an instance variable? It seems
like the coupling between steps is the same, but the coupled state is
stored differently. Maybe that’s the point - stored differently.

I guess my view is that having the state out front in the scenario is
preferable whenever possible (without cluttering up the feature with
noise) because it’s clear, and there’s less risk of a gap opening up
between what the step appears to do given its name, and what it
actually does when it runs. I take this gap seriously because I put a
great deal of trust our features.

boolean attributes of a policy, but it doesn’t read so well.
I don’t think that’s nasty, it seems entirely appropriate for that
type of problem. It sounds like the type of acceptance tests I hear
people like Keith Braithwaite talking about putting together for
traders using Excel and Fit, and they seem to work really well.

Thinking about this some more though, maybe there’s an argument for
breaking the feature up into multiple features, and using Background
to set up the common state of the objects, then have a few scenarios
that build on this with different steps to tweak the objects. Just
another idea - it’s really hard to judge without seeing more of the
specific features.

“With …” would mean steps that were coupled to the “last mentioned
thing”. That seems like a different kind of coupling - there is only
one piece of state involved (the last thing) rather than a map of
named things. But it’s less explicit and implies that the “last thing”
needs to be updated by each step that mentions things.

I know what you mean, and it would certainly make for nice readable
scenarios. My worry is how maintainable the steps would be in the long
run. I’m used to seeing steps like this:

Given /the Policy has a secondary risk/ do
Policy.count.should == 1
policy = Policy.first
policy.secondary_risk = true
policy.save
end

Which are pretty explicit and leave no room for accidental abuse. What
the OP suggested would give you something more like this:

Given /a Policy/ do
@it = Factory(:policy)
end

With /a secondary risk/ do
@it.secondary_risk = true
@it.save
end

I dunno actually. Now I type it out it doesn’t seem so bad :slight_smile:

Matt, going back to Mark’s example, it sounds like you lean towards
the latter (i.e. repeat 'Reach from the Stars for ‘Halo 3’ throughout
the scenario). Is that correct?

I guess my heuristic is something like this:

  1. If I can simply refer to “the Widget” then I do, wherever possible.

  2. If some attribute of the Widget is important in the scenario, I’ll
    explicitly set that attribute, and mention it again later in the
    assertions. e.g.
    Given a Widget named “Foo”
    When I delete the Widget
    Then I should see the text “bye bye Foo”

  3. If I have to refer to multiple objects of the same class in one
    scenario, then I use names to differentiate between them. e.g.
    Given some Widgets named “Foo, Bar”
    When I delete the Widget “Foo”
    Then I should see 1 Widget
    And I should see the text “Bar”

Matt W.
http://blog.mattwynne.net
http://www.songkick.com


#14

I like that heuristic Matt.

Actually coupling via the database is quite different to instance
variables. The database state would exist if you followed through the
scenario without cucumber e.g. manually.

It occurred to me you could avoid the table like this too:

Given a policy with a PCF practice state, secondary risk and something
else

Given /^a policy with (.+)$/ do | attributes |

create policy

attributes.split(/(?:(?:,|\sand)\s)/).each do | attribute |
# apply attributes “a PCF practice state”, “secondary risk”,
“something else”
end
end

Josh


#15

end

I dunno actually. Now I type it out it doesn’t seem so bad :slight_smile:

As previously mentioned in the thread another way to phrase this is with
step tables. Here is the code I use:

http://gist.github.com/59007
(related blog post:
http://www.benmabey.com/2009/02/05/leveraging-test-data-builders-in-cucumber-steps/)

I have been using instance variables in my steps (but naming them after
the model, i.e. @policy) but Matt’s DB solution is nice in some
respects. Both ways fall apart when you have multiple polices, but in
that case you should probably be passing in the name or some other
identifying aspect of the model. Anyways, it seems like a pattern is
emerging on how to carry state to other steps when you have to. I was
bored so I combined both approaches:

module ObjectLocators

def the_policy
if @policy
@policy
else
case Policy.count
when 0
raise “There is no @policy variable defined and no policy in the
DB! Establish state in previous step or create a new policy.”
when 1
Policy.first
else
raise “There are multiple policies in DB and no @policy variable
set! Please disambiguate the state in previous step.”
end
end
end

end

World { |world| world.extend(ObjectLocators) }

(this code is here: http://gist.github.com/79470)

Like I said, I was bored and haven’t really tried this. I don’t know if
I even like it, but I thought extracting out the patterns would be
useful. You could leverage factories just as I do in my previous gist
to provide locator (locater?) for all of your models.

Great thread BTW.

-Ben


#16

It’s SRP applied to cucumber steps - just do it - keep your steps
small and composable

Sent from my iPhone


#17

On 15 Mar 2009, at 16:52, Ben M. wrote:

end
@it.save
I have been using instance variables in my steps (but naming them
if @policy
variable set! Please disambiguate the state in previous step."

Like I said, I was bored and haven’t really tried this. I don’t
know if I even like it, but I thought extracting out the patterns
would be useful. You could leverage factories just as I do in my
previous gist to provide locator (locater?) for all of your models.

We have some very similar code deep in the bowels of Songkick’s
features folder that is a little scrappy, but does help us solve this
problem quite nicely.

Basically there’s a regular expression that matches on phrases of the
following form:

the Widget
the Widget “Foo”
“Foo”

So you can use that in your step matchers like this:

When /I delete (#{THE_THING})/ |identifier|
thing_to_delete = identified_model(identifier)
end

If you want to remember something just by the “Foo” label, you have to
throw it into a collection, imaginatively named ‘stuff’, as you do so:

stuff[“Foo”] = Factory(:widget, :name => “Foo”)

As I say it’s a little scrappy as it’s something we threw together
ages ago and haven’t really felt the need to revisit, but hopefully it
will give someone some ideas:
http://gist.github.com/79496

Matt W.
http://blog.mattwynne.net
http://www.songkick.com