Write Great Cucumber Tests

Posted Mar 14th, 2016

Cucumber Testing

Using Cucumber with outlined best practices in your automated tests ensures that your automation experience will be successful and that you’ll get the maximum return on investment (ROI). Let’s review some important best practices needed before you start developing Cucumber tests.

Writing Features

Feature files help non-technical stakeholders engage and understand testing, resulting in collaboration and bridging the communication gap. For this reason, well-written feature files can be a valuable tool for ensuring teams use the BDD process effectively.

Here are some suggested standards for Cucumber Feature files:

Organization Feature files can live at the root of the /features directory. However, features can be grouped in a subfolder if they describe a common object. The grouped filenames should represent the action and context that is covered within.
Feature Files Every *.feature file consists in a single feature, focused on the business value.
Gherkin Template Feature: Title (one line describing the story)

Narrative Description: As a [role], I want [feature], so that I [benefit]

Scenario: Title (acceptance criteria of user story)
Given [context]
And [some more context]...
When [event]
Then [outcome]
And [another outcome]...

Scenario: ...
Background The background needs to be used wisely. If you use the same steps at the beginning of all scenarios of a feature, put them into the feature’s background scenario. The background steps are run before each scenario.
Scenarios Keep each scenario independent. The scenarios should run independently, without any dependencies on other scenarios.
Scenario Outline If you identify the need to use a scenario outline, take a step back and ask the following question: Is it necessary to repeat this scenario ‘x’ amount of times just to exercise the different combination of data? In most cases, one time is enough for UI level testing.
Write Declarative Scenarios, Not Imperative The declarative style describes behavior at a higher level, which I think improves the readability of the feature by abstracting out the implementation details of the application.

Example: Imperative

Scenario: User logs in
Given I am on the homepage
When I click on the "Login" button
And I fill in the "Email" field with "me@example.com"
And I fill in the "Password" field with "secret"
And I click on "Submit"
Then I should see "Welcome to the app, John Doe"

Example: Declarative

Scenario: User logs in
Given I am on the homepage
When I log in
Then I should see a login notification

Just avoid unnecessary details in your scenarios.
Given, When, and Then Statements I’ve often seen people writing the Gherkin syntax confuse when to put the verification step in the Given, When, Then sequence. Each statement has a purpose.
    • Given is the pre-condition to put the system into a known state before the user starts interacting with the application

    • When describes the key action the user performs

  • Then is observing the expected outcome

Just remember the ‘then’ step is an acceptance criteria of the story.
Tagging Since tags on features are inherited by scenarios, please don’t be redundant by including the same tags on scenarios.

Write Step Definitions

Cucumber doesn't know how to execute your scenarios out of the box. It needs Step Definitions to translate plain text Gherkin steps into actions that will interact with the system. Step definitions are defined in Ruby files under features/step_definitions/*_steps.rb.

Here are some suggested standards for Cucumber Step Definition files:

Step Definitions Keep the step definitions unique. If your step definition names aren’t unique, then you will find during runtime the following exception is thrown - ambiguous match.
Hard-coding As you know you shouldn't be hard coding parameters into your code. This applies to site URL’s as well to allow flexibility to globally change the value.
Reusable Objects At the beginning of any automation project, you need to think about scalability and maintainability. A good programming practice is Don’t Repeat Yourself (or DRY) by creating reusable code. You will find many different ways to share code between Cucumber scenarios. Be careful!
    • Call other step definitions. Call step definitions from other step definitions by calling steps helper. (Avoid)

    • Use many_steps helper. It does everything that steps helper does, but gives you meaningful stack traces in case something goes wrong. (Avoid)

  • Use a Page Object Pattern should be mapped to a Ruby class file, and each method within the class represents a page object on the page. (Better Choice)

Why use the Page Object Pattern?

    • Readable DSL

    • Promotes reusable code

  • Centralizes UI coupling — one place to make changes rather than multiple places throughout step definitions
Code No sleep statements. It is better to use method or function with a built-in timeout.
RSpec Expectations The rspec-expectations library is bundled with many built-in matchers for testing validation. Each of the matchers can be used with expect(..).to or expect(..).not_to to define positive and negative expectations respectively on an object under test. I recommend using rspec-expectations matchers over Selenium matchers for Ruby testing frameworks.

Cucumber Configuration

Adding Cucumber to a Ruby project is easy. Some of the configuration files needed include:

cucumber.yml It simplifies command-line execution by defining reusable profiles within the cucumber.yml file.
Gemfile The Gemfile is used to manage dependencies for a Ruby project. We should also pin the versions of these Ruby gems. If you don’t pin a Ruby version, it will auto update and break your automation.
Rakefile Rakefile is a software task management and build automation tool. It allows you to specify tasks and describe dependencies as well as group tasks in namespaces.
support/env.rb The support/env.rb is an environment configuration file for Cucumber. This file is designed to provide flexibility by allowing you to do things easily, like toggle your execution environment from local to remote. To fully understand all the capabilities of this support file, you should take more time to read up on all of the capabilities.

At the End of the Day

BDD (Cucumber) allows for team collaboration early in the planning and development phases. Keep the numbers down. Ask yourself and the team: “If I can write a low-level test for this user story, should I write an UI acceptance test?” We should automate only the things that need to be automated at the UI level. It is a known fact that low-level tests are more reliable compared to UI tests. Cucumber is code, and all types of programming require thoughts upfront before writing automated tests. It is so important to lay a test automation foundation that embraces coding standards and follows design patterns that everyone will follow during automation development.


Are you interested in learning more about Cucumber? Join me and Ashley Hunsberger at STPCon when we conduct another workshop.

Greg Sypolt (@gregsypolt) is a senior engineer at Gannett and co-founder of Quality Element. He is a passionate automation engineer seeking to optimize software development quality, while coaching team members on how to write great automation scripts and helping the testing community become better testers. Greg has spent most of his career working on software quality — concentrating on web browsers, APIs, and mobile. For the past five years, he has focused on the creation and deployment of automated test strategies, frameworks, tools and platforms. 

Written by

Greg Sypolt


Automated testing