-
Notifications
You must be signed in to change notification settings - Fork 0
Step Definitions
Step definitions are defined in ruby files under features/step_definitions/*_steps.rb
. Here is a simple example:
Given /^I have (\d+) cucumbers in my belly$/ do |cukes| # Some Ruby code here end
A step definition is analogous to a method definition / function definition in any kind of OO/procedural programming language. Step definitions can take 0 or more arguments, identified by groups in the Regexp (and an equal number of arguments to the Proc).
Some people are uncomfortable with Regular Expressions. It’s also possible to define Step Definitions using strings and $variables like this:
Given "I have $n cucumbers in my belly" do |cukes| # Some Ruby code here end
In this case the String gets compiled to a Regular Expression behind the scenes: /^I have (.*) cucumbers in my belly$/
.
Then there are Steps. Steps are declared in your features/*.feature
files. Here is an example:
Given I have 93 cucumbers in my belly
A step is analogous to a method or function invocation. In this example, you’re “calling” the step definition above with one argument – the string “93”. Cucumber matches the Step against the Step Definition’s Regexp and takes all of the captures from that match and passes them to the Proc.
Step Definitions start with a preposition or an adverb (Given, When, Then, And, But), and can be expressed in any of Cucumber’s supported Spoken languages. All Step definitions are loaded (and defined) before Cucumber starts to execute the plain text.
When Cucumber executes the plain text, it will for each step look for a registered Step Definition with a matching Regexp. If it finds one it will execute its Proc, passing all groups from the Regexp match as arguments to the Proc.
The preposition/adverb has no significance when Cucumber is registering or looking for Step Definitions.
Also check out Multiline Step Arguments for more info on how to pass entire tables or bigger strings to your step definitions.
When Cucumber finds a matching Step Definition it will execute it. If the block in the step definition doesn’t raise an Exception, the step is marked as successful (green). What you return from a Step Definition has no significance what so ever.
When Cucumber can’t find a matching Step Definition the step gets marked as yellow, and all subsequent steps in the scenario are skipped. If you use --strict
this will cause Cucumber to exit with 1
.
When a Step Definition’s Proc invokes the #pending
method, the step is marked as yellow (as with undefined ones), reminding you that you have work to do. If you use --strict
this will cause Cucumber to exit with 1
.
When a Step Definition’s Proc is executed and raises an error, the step is marked as red. What you return from a Step Definition has no significance what so ever. Returning nil or false will not cause a step definition to fail.
Steps that follow undefined, pending or failed steps are never executed (even if there is a matching Step Definition), and are marked cyan.
Steps can be defined using strings rather than regular expressions. Instead of writing
Given /^I have (.*) cucumbers in my belly$/ do |cukes|
You could write
Given “I have $count cucumbers in my belly” do |cukes|
Note that a word preceded by a $ sign is taken to be a placeholder, and will be converted to match .*
. The text matched by the wildcard becomes an argument to the block, and the word that appeared in the step definition is disregarded.
Consider these step definitions:
Given /Three (.*) mice/ do |disability|
end
Given /Three blind (.*)/ do |animal|
end
And a plain text step:
Given Three blind mice
Cucumber can’t make a decision about what Step Definition to execute, and wil raise a Cucumber::Ambiguous
error telling you to fix the ambiguity.
Running the plain text step will match the Regexp of both step definitions and raise Cucumber::Ambiguous
. However,
if you run Cucumber with --guess
, it will guess that you were aiming for the step definition with 2 match groups.
There is ranking logic that gets invoked when the option is turned on:
- The longest Regexp with 0 capture groups always wins.
- The Regexp with the most capture groups wins (when there are none with 0 groups)
- If there are 2+ Regexen with the same number of capture groups, the one with the shortest overall captured string length wins
- If there are still 2+ options then an Ambiguous error is raised
So if you try --guess
with the mice above, Cucumber will pick /Three blind (.*)/
, because “mice” is shorter than “blind”.
Consider guess mode a workaround. We still recommend you try to have unambiguous regular expressions. When you have a lot of step definitions you quickly lose track of the situations where cucumber will apply guessing logic, and that can lead to some surprises.
In Cucumber you’re not allowed to use a regexp more than once in a Step Definition (even across files, even with different code inside the Proc), so the following would cause a Cucumber::Redundant
error:
Given /Three (.*) mice/ do |disability|
# some code
end
Given /Three (.*) mice/ do |disability|
# some other code
end