Cucumber is a framework that uses Gherkin Syntax to drive Behavior Driven Development in your test infrastructure. (Need a quick primer on BDD? Check out this blogpost) In this blog post, I am going to take a glance Gherkin keywords and demonstrate the power of Cucumber Expression — the alternative to regex step definitions.
Gherkin keywords have specific functionalities, such as defining features. Every feature consists of scenarios having a certain scope, and every scenario consists of steps defined by regex or Cucumber Expression in step definitions.
Name of the .feature file.
There can be only one feature keyword per .feature file.
It can get description words below itself.
Feature: User Features
Application should be tested against possible behaviors of registered users.
Scenario: Logging in with registered user
Note: The description line shown above can also be used with Background, Rule, Scenario, or Scenario Outline (and with their aliases) unless a keyword is used beforehand.
Also note that some keywords such as Feature get semicolons as a suffix and do not work without it.
A keyword level between feature and scenario.
It can be used to group certain scenarios having the same rule.
Each rule can have its own background block.
Note: Rule keyword is pretty new, and certain test case management tool integrations may support it. Also, Cucumber Extensions on some IDEs do not group scenarios by Rule keyword, so they can not be executed separately.
Background:
Given go to home page
Rule: User must be logged in
Background:
Given sign in with 'username' and 'password'
Scenario: Logging out
When click logout button on home page
Then verify user is logged out on home page
Rule: User must be non-logged in
Scenario: Verify non-logged in on refreshed page
When go to home page
Then verify user is not logged in
- Name of the Test Case.
- It contains Given, When, Then, And, and But keywords.
- First scenario step.
- It is usually used to describe the initial context.
Scenario: Signing in
Given home page is open
When click on sign in button
And fill areas with 'username' and 'password'
Then 'username' is displayed on top right corner
But sign in button shouldn't be displayed
- All Cucumber steps can be written with * keyword.
- It is best suited for listing similar steps.
Scenario: Making halva
Given I am hungry
* I have oil
* I have flour
* I have sugar
When I make halva and eat it
Then I am not hungry
- Name of the Test Case.
- This keyword is used to run a scenario with different values consecutively. Thus, enables us to do data-driven testing.
- It contains Given, When, Then, And, and But keywords.Note: The placeholders are written inside of <> characters.
- This keyword is used along with Scenario Outline to specify the values to be replaced with placeholders.
Scenario Outline: Shop cart item removal
Given there are items in the cart
When I remove items from the cart
Then verify items left in the cart
Examples:
| start | remove | left |
| 12 | 5 | 7 |
| 20 | 5 | 15 |
- Background is used for the general steps that should be executed for every scenario.
- It can be used with the Rule keyword, affecting only the scenarios nested inside that specific Rule.
Background:
Given go to home page
And sign in with 'username' and 'password'
Scenario: Logging out
When click logout button on home page
Then verify user is logged out on home page
Scenario: Verify login on refreshed page
When go to home page
Then verify user is logged in
To understand Cucumber Expressions, we need to understand what a step definition is.
Scenario steps are high-level statements, and they actually don’t have any meaning as far as a programming language is concerned. To give them a purpose, we need to define what they do in the background. That is called the “step definition.
IDEs like RubyMine usually create step definitions with regex.
Cucumber Expression provides us with a different way to create a step definition. Let’s compare them with each other.
#RegEx step definition
And(/^create a user named "([^"]*)"$/) do |arg|
pending
end
#Cucumber Expression step definition
And("create a user named {string}") do |arg|
pending
end
As you can see from the example above, Cucumber Expression does not directly use a regex inside the step definition. It handles it differently.
The text between curly braces in the example above is called parameters. There are some built-in parameters that Cucumber provides us. These are:
Built-in parameter |
Description |
{int} |
Matches an integer. E.g. 18 or -59. |
{float} |
Matches a float. E.g. 9.2 or -8.3. |
{word} |
Matches a word without spaces. E.g. kloia. |
{string} |
Matches a string with a double or single quote. E.g. “kloia company” |
{} |
Matches anything (/.*/). |
{bigdecimal} |
Matches the same as {float}, converts it to BigDecimal if supported. |
{double} |
Matches the same as {float}, converts it to 64 bit float if supported. |
{biginteger} |
Matches the same as {int}, converts it to BigInteger if supported. |
{byte} |
Matches the same as {int}, converts it to 8-bit signed integer if supported. |
{short} |
Matches the same as {int}, converts it to 16-bit signed integer if supported. |
{long} |
Matches the same as {int}, converts it to 64-bit signed integer if supported. |
If the parameters above do not meet your needs and you want to create a custom parameter using your own regex, that is also possible.
There are four main fields to create a custom parameter.
Argument |
Description |
name |
This is the name of your parameter. This is what is used between curly brackets. For the example above, it is {name}. |
regexp |
Regular Expression to capture the contents of the argument. |
type |
The return type of the transformer. |
transformer |
Needs to have at least arity 1 if regex does not have any capture groups. Otherwise, argument number must be equal to the regex’s capture group count. Note: Transformer should be a function. |
Let’s say that we want to give a person’s name in the step and create a Person object with it. Here is the ParameterType configuration and step definition:
ParameterType(
name: 'name',
regexp: /"([^"]*)"/,
type: Person,
transformer: -> (arg) {Person.new(name: arg)}
)
And("create a user named {name}") do |person|
puts person
puts "id: " + person.id
puts "name: " + person.name
puts "age: " + person.age
end
The person class used inside the transformer:
class Person
attr_accessor :id, :name, :age
def initialize(options = {})
self.id = options[:id] || "unknown"
self.name = options[:name] || "unknown"
self.age = options[:age] || "unknown"
end
end
The feature file:
Feature: Step definition examples
Scenario: creating step definitions
And create a user named "kloia"
Output of the code:
#
id: unknown
name: kloia
age: unknown
You might realize the example given above might not be the best way to handle objects, but it is a good example to demonstrate the power of Cucumber Expressions.
You may want to refer Cucumber Expression page on Git Hub.
As a finishing line, let me share an idiom I love
“To run with salt to anyone who says I have a cucumber.” - Turkish Idiom
Meaning: Trying to help everyone without thinking afterward and ending up in a bad situation.
But hey, we are going to run test cases with cucumber. There is a difference!😀