Quality Assured

Gherkin BDD: Ruby edition

January 15, 2016

Time for a second round of behavorial test automation, this time with ruby! My python post contains a bdd tutorial. This post is more focused on the ruby aspect and technology stack, so I will not discuss bdd all that much here.

For this example we will be using the following stack:

The example repo can be found here.

Setup from the readme:

git clone git@github.com:StephenDavidson/ruby-bdd-cucumber.git
cd cucumber-examples/ruby
gem install bundler
bundle install

Running the tests:

cd cucumber-examples/ruby
cucumber # run all feature files
cucumber features/ # run all feature files in the given folder
cucumber features/search.feature # run the search.feature file only

Once we have the repo setup, we can take a look at the project as a whole:

Project_name
├── config # contains all hardcoded strings and settings
|   └── production.yaml # production configuration values
├── features
|   ├── pages # page objects to be used by step definitions
|   |   ├── base.rb # base page that all pages inherit from
|   |   ├── home.rb # home page
|   |   └── results.rb # search results page
|   ├── step_definitions # contains all test steps
|   |   ├── common_steps.rb # common steps between features
|   |   └── search_steps.rb # feature specific steps
|   ├── support # 
|   |   ├── env.rb # environmental setup
|   |   └── hooks.rb # contains global before and after hooks for tests
|   └── search.feature # feature file that contains test scenarios for the search feature
├── lib # contains services, handlers, and other scripts
|   └── instance_creator.rb # global factory to create users for example
├── .gitignore # list of files to ignore when pushing to github
├── .travis.yml # continuous integration
├── Gemfile # required packages list
├── Gemfile.lock # version control
└── README.md # readme

We have four primary directories: config, features, and lib.

First let us look at our config folder. Inside, I have yaml files separated by environment. These files should include our hard-coded strings, typically urls, user information, and api keys. I prefer to keep my config files separated by environment because tests isolated by the environment they run on.

The features folder contains all of our front-end ui automation tests including the test setup, tear down, steps, and page objects. It is also one of the largest folders and needs a bit more breakdown. It contains the pages, step_definitions,and support folders.

The pages folder contains all of our page objects. These page objects act as aliases for css in the web application we are testing. That way, we can go to one central location to maintain our css strings. Inside we have a base page that all the other pages will inherit from. We can add common functions here that all of our pages may need, or common css like a success class used through out the site we test. We use site prism as a decorator for our pages, so that we can split the page objects into easy to read sections.

The step_defintions folder contains a common_steps.rb and search_steps.rb file. The common steps are, as you would guess, steps that are shared across tested. Many times these end up being capybara wrappers. The search steps are specific to our search feature, and are unique steps that involve the search functionality only. It can be difficult to find a balance between common steps and search steps. My rule of thumb is that common steps of the same gherkin type should never be repeated in a scenario (eg. given and given or when and when). It is a rule of thumb though, so it will not always be the case. You just want to prevent your scenarios from becoming 50 common steps, which have to be adjusted constantly.

The support folder contains the env.rb file and hooks.rb file. The env file is used to create our test environment. This is where we load our yaml file and set the environment we are in. It is also where we set our browser and load any globals we want for our tests. The hooks file is meant to contain our before and after functions for our test suite. In the case of this repo, I have placed our browser teardown. It reduces clutter from our tests, that is a given no matter how we run the test.

The lib folder contains all of our locators, services, and handlers for the project. The only file in here currently is the instance creator. The instance creator is a class that we make global so that tests can create dynamic data. The instance creator uses the factory design pattern in order to allow us to choose users on the fly, or choose a certain credit card for testing, without having to rely on hard-coded strings on our tests. Instead we use the instance creator to load yaml files, and make the objects for us.

On a technology related note I chose capybara, because it currently is the most fleshed out async selenium wrapper for ruby. It handles all of the timing for you, so that waits will almost never be needed. I also think that using the gems faker and factory girl would help scale data generation for the test automation suite.

That is a brief overview how I envision a ruby repository. Please feel free to reach out to me with your thoughts.


Stephen Davidson

Written by Stephen Davidson a passionate software quality nerd

© 2025, Stephen Davidson