In the Building a real web application with Cucumber (Intermediate) recipe, we completed five simple user stories driven by Cucumber, and we learnt how to drive a Rails web application development using Cucumber in a BDD style.
Gherkin provides various kinds of expressive syntax. In this recipe, we are going to learn various kinds of skills and tips with Cucumber Gherkin DSL, and how to write readable, organized, and reusable Gherkin to help us solve real-world problems.
We will reuse the Rails application, cucumber_bdd_how_to
, which we created in the Writing your first Hello World feature (Simple) recipe, so please cd
into that directory to get prepared.
In the following sections, a number of useful Gherkin tips are introduced and covered exhaustively.
Feature: Github account management In order to manage my profile, repositories and my SSH Keys As a registered developer I Should be able to log into system and manage my account Scenario: Change my avatar Given I logged into Github with account "Wayne Ye" When I click my avatar to go to the "Your Profile" page Then I can change my avatar with "Wayne.png" Scenario: View my repositories Given I logged into Github with account "Wayne Ye" When I click my avatar to go to the "Your Profile" page And I click on "Repositories" hyperlink Then I should be able to see all my repositories Scenario: Add a SSH KeyGiven I logged into Github with account "Wayne Ye" When I click my avatar to go to the "Your Profile" page And I click on "SSH Keys" hyperlink Then I add a new SSH key
Background
:Feature: Github account management In order to manage my profile, repositories and my SSH Keys As a registered developerI Should be able to log into system and manage my account Background: Given I logged into Github with account "Wayne Ye" When I click my avatar goto the "Your Profile" page Scenario: Change my avatar Then I can change my avatar with "Wayne.png" Scenario: View my repositories And I click on "Repositories" hyperlink Then I should be able to see all my repositories Scenario: Add a SSH Key And I click on "SSH Keys" hyperlink Then I add a new SSH key
Whenever possible, use Gherkin Background
to centralize the scenario shared steps, be DRY (don't repeat yourself), and get better maintainability!
Feature: User registration In order to shop in ABC online shop As a userI should be able to register an account through registration page Scenario: register with valid information When I am on the registration page of ABC online shop And I fill the "Full Name" form with "Wayne Ye" And I fill the "Address" form with "123 Main Street" And I fill the "Email" form with "[email protected]" And I fill the "Password" form with "asdf" Then I should be redirected to registration success page
Feature: User registration In order to shop in ABC online shop As a userI should be able to register an account through registration page Scenario: register with valid information When I am on the registration page of ABC online shop And I fill the form with the following value | Full Name| Address | Email | Password | | Wayne Ye | No 12 Pt Street| [email protected] |asdf| Then I should be redirected to registration success page
Scenario: instance messenger online When I log into ABC social website And I open up the IM tab Then I should see my online friends | Mark | | Sean | | Shelly | | Wendy |
Background: When I am on the registration page Scenario: user registration When I fill "email" field with "" And I press "Register" button Then I should see error message "Email cannot be blank" When I fill "email" field with "wayne" And I press "Register" button Then I should see error message "Please input valid Email address" And I fill "password" field with "" And I press "Register" button Then I should see error message "Password cannot be blank" And I fill "password" field with "asdf" And I press "Register" button Then I should see error message "Password is too short"
Scenario Outline
:Scenario Outline: user registration When I fill "<field_name>" field with "<value>" And I press "Register" button Then I should see error message "<error_message>" Examples: |field_name| value | error_message | | Email | | Email cannot be blank | | Email | wayne | Please input valid Email address | | Email |[email protected]| Email has already been taken | | Password | | Password cannot be blank | | Password | asdf | Password is too short |
By utilizing Scenario Outline, the feature looks clean and easy, and it refrains from writing duplicate steps. Additionally, we can quickly find out missed cases because of its tidy text. For example, in the previous case, we can easily point out that we lack the maximum length check for both the e-mail and password.
Scenario: User registration When the user clicks "Register" Then an Email should be sent out with content: """ Dear customer, Thank you for registering at ABC website! Please click the following link to activate your account! http://foo-web.com/user/wayne/activation """
Cucumber::Ast::Docstring
:Then /^an Email should be sent out with content:$/ do |string|p string.class # Cucumber::Ast::DocString p string # "Dear customer, Thank you for registering at ABC website! Please click the following link to activate your account! http://foo-web.com/user/wayne/activation" end
There are two extra tips for organizing Cucumber features and writing better features.
Gherkin allows you to add meaningful tags, for example:
@important
or @MMV
@require_login
@todo
or @wip
Tag(s) can be applied to features or scenarios; scenarios, scenario outlines, or examples will inherit any tags that exist on the containing feature.
Tag(s) are pretty useful and provide many benefits. For example, they can help in organizing and filtering features:
@mandatory
:$ cucumber --tags @mandatory
@todo
ones:$ cucumber --tags ~@todo
@finished
and @integration
features:$ cucumber --tags @finished --tags @integration
$ cucumber --tags @dev:4,@qa:6
Cucumber will fail if there are more than four @dev
features or more than six @qa
features, even if all the features passed. This tip will be pretty useful in the Kanban development methodology (a scheduling system invented by Toyota for the Lean and Just-in-Time productions) because we want to limit the number of Working in Progress features.
Apply tag logic by using hooks. We can add a block of Ruby code before/around/after a specific tag. This is massively useful, for example, because we can implement login logic before all features/scenarios marked with a @require_login
tag:
Before('@require_login') do # Put login logic here end After('@require_login') do # Perform logout logic end
When we run the @require_login
tag, the login logic hook will be executed automatically. Here it just demonstrates the tagged hooks. There are also scenario hooks, step hooks, and global hooks.
Do you remember in the beginning of the previous recipe, we wrote a Gherkin feature for the first story:
Feature: Write blog As a blog owner I can write new blog post Scenario: Write blog Given I am on the blog homepage When I click "New Post" link And I fill "My first blog" as Title And I fill "Test content" as content And I click "Post" button Then I should see the blog I just posted
Every step in this feature is granular; it describes each action used. Steps like these are called imperative steps (or communicative); as a comparison, another pattern of writing Gherkin is declarative (or informative), which suggests describing the user story over recording the user's actions.
For example, writing the previous feature in the declarative style will be as follows:
Feature: Write blog As a blog owner I can write new blog post Scenario: Write blog Given I am on the blog homepage When I write a new blog post Then I should see the blog I just posted
A declarative step usually hides more details and provides better readability for business people. Many people prefer declarative steps over imperative steps since imperative steps could be brittle because they are usually tightly coupled with UI or a serial of business logic, whereas both of them could be changed as per the requirement.
In the older version of Cucumber, there used to be a web_steps.rb
generated under the step_definitions
directory every time Cucumber got installed. However, to avoid people writing imperative steps, Aslak Hellesøy (the co-author of Cucumber) removed it. His original statement is as follows:
"The reason behind this is that the steps defined in web_steps.rb leads people to write scenarios of a very imperative nature that are hard to read and hard to maintain. Cucumber scenarios should not be a series of steps that describe what a user clicks. Instead, they should express what a user does."
However, an imperative step is not always bad. Using imperative steps in some cases is more appropriate and natural than declarative steps. It is usually simple to read and understand, so the suggestion here is trying to write declarative steps but using imperative steps whenever the need arises.
3.145.12.156