🚀  Our new eBook is out – “CI/CD for Monorepos.” Learn how to effectively build, test, and deploy code with monorepos. Download now →

Setting Up the BDD Stack on a New Rails 4 Application


This tutorial guides you through generating a new Rails 4 application with RSpec and Cucumber as testing tools.

If you’d like to learn how to set up a BDD stack on a Rails 5 application, this tutorial is the best next read for you.

RSpec is a testing tool often used for writing unit tests, while Cucumber is a tool for writing acceptance tests. Both tools are popular choice for behavior-driven development (BDD).

In the tutorial, we assume you are working on a Unix-like operating system.


  • Ruby.
  • SQLite (sqlite-devel package in Red Hat based distributions or libsqlite3-dev in Debian based distributions).

Create the application

To generate a new Rails application, we will need rails gem. Install the latest version of rails with:

gem install rails

Generate a new Rails application called myapp:

rails new --skip-test-unit --skip-bundle myapp

The --skip-test-unit option skips configuring test.unit. In the tutorial, we use RSpec instead.

The --skip-bundle option prevent running bundle install automatically. We will do that manually:

cd myapp
bundle install --path vendor/bundle

The --path parameter tells the bundle install command to install gems in the myapp/vendor/bundle directory. If you leave off the parameter, gems will be installed globally. It’s a good practice to keep gems installed locally – especially if you are working on more than one Ruby application on the development machine.

Installing debugger gem can fail if you have Ruby 2 on your development machine:

An error occurred while installing debugger (1.6.8), and Bundler cannot
Make sure that gem install debugger -v '1.6.8' succeeds before bundling.

If that happens, open Gemfile in the application directory and replace gem 'debugger' with gem 'byebug'. Run bundle install --path vendor/bundle again an this time gems should install successfully. Byebug is a debugger that supports Ruby 2.

Install RSpec

Add rspec-rails gem to the development and test groups of your Gemfile.

group :development, :test do
  gem 'rspec-rails'

Install the gem:


Bootstrap the application with RSpec:

bundle exec rails generate rspec:install

The task will generate RSpec configuration files.

Install shoulda-matchers

shoulda-matchers lets us spec common Rails functionality, like validations and associations, with less code.

Add shoulda-matchers gem to the test group of your Gemfile:

group :test do
  gem 'shoulda-matchers'

Install the gem:


Before you can use shoulda-matchers, you need to configure it by choosing the test framework and features of shoulda-matchers you want to use. Open spec/rails_helper.rb and add the following block to the end:

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails

You can find more info about configuring shoulda-matchers in the offical readme.

Install factory_girl

factory_girl is a library for setting up Ruby objects as test data. It’s essentially a fixtures replacement.

Add factory_girl_rails gem to the development and test groups of your Gemfile:

group :development, :test do
  gem 'rspec-rails'
  gem 'factory_girl_rails'

Install the gem:


factory_girl allows you to create objects that are needed in tests without providing a value for each required attribute. If you don’t provide a value for a required attribute factory_girl will use the default value that you defined in factory’s definition.

Make Sure Everything is Connected and Working

Let’s create an example Post model and write specs that will verify that RSpec is working correctly:

$ bundle exec rails generate model Post title:string content:text
invoke active_record
create db/migrate/20140926125040_create_posts.rb
create app/models/post.rb
invoke rspec
create spec/models/post_spec.rb
invoke factory_girl
create spec/factories/posts.rb

Notice, the generator also creates a model spec and a Post factory. That’s the reason why we included the rspec-rails and factory_girl_rails gems in the development group of the Gemfile.

Run the migration that will add the new posts table to the database:

bundle exec rake db:migrate

Define a post factory:

# spec/factories/posts.rb
FactoryGirl.define do
  factory :post do
    title "My first post"
    content "Hello, behavior-driven development world!"

Update the spec to validate post’s title and content:

# spec/models/post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  it { is_expected.to validate_presence_of(:title) }
  it { is_expected.to validate_length_of(:title).is_at_least(5) }
  it { is_expected.to validate_presence_of(:content) }
  it { is_expected.to validate_length_of(:content).is_at_least(10) }

And update the Post model with validation definitions:

# app/models/post.rb
class Post < ActiveRecord::Base
  validates :title, presence: true, length: { minimum: 5 }
  validates :content, presence: true, length: { minimum: 10 }

Run Post specs:

$ bundle exec rspec spec/models/post_spec.rb

Finished in 0.01982 seconds (files took 1.26 seconds to load)
4 examples, 0 failures

You can see that specs pass which means that RSpec, shoulda-matchers and factory_girl are properly configured.

Install Cucumber

Add cucumber-rails and database_cleaner gems to the test group of the Gemfile:

group :test do
  gem 'shoulda-matchers'
  gem 'cucumber-rails', require: false
  gem 'database_cleaner'

The database_cleaner gem is not required, but it will make your development easier. It’s used to ensure a clean database state for testing.

Install the gems:


Bootstrap the application with Cucumber:

bundle exec rails generate cucumber:install

The task will generate Cucumber configuration files and set up database for Cucumber tests.

Install selenium-webdriver

To be able to run Cucumber scenarios which use JavaScript you need selenium-webdriver. Add it to the test group of your Gemfile:

group :test do
  gem 'cucumber-rails', require: false
  gem 'database_cleaner'
  gem 'selenium-webdriver'

And install it:


Make sure Cucumber is working correctly

To do that, let’s develop a simple feature. In the scenario, a user will visit the homepage and see that a post is displayed:

# features/home_page.feature
Feature: Home page

  Scenario: Viewing application's home page
    Given there's a post titled "My first" with "Hello, BDD world!" content
    When I am on the homepage
    Then I should see the "My first" post

Run the scenario and you will see snippets for implementing steps:

$ bundle exec cucumber features/home_page.feature

You can implement step definitions for undefined steps with these snippets:

Given(/^there's a post titled "(.*?)" with "(.*?)" content$/) do |arg1, arg2|
  pending # express the regexp above with the code you wish you had

When(/^I am on the homepage$/) do
  pending # express the regexp above with the code you wish you had

Then(/^I should see the "(.*?)" post$/) do |arg1|
  pending # express the regexp above with the code you wish you had

Let’s copy those steps into features/step_definitions/home_page_steps.rb and edit them:

# features/step_definitions/home_page_steps.rb
Given(/^there's a post titled "(.*?)" with "(.*?)" content$/) do |title, content|
  @post = FactoryGirl.create(:post, title: title, content: content)

When(/^I am on the homepage$/) do
  visit "/"

Then(/^I should see the "(.*?)" post$/) do |title|
  @post = Post.find_by_title(title)
  expect(page).to have_content(@post.title)
  expect(page).to have_content(@post.content)

In these steps we create a post using factory_girl, visit the homepage and check if the post is displayed.

If you run the scenario again, you will see that it fails since the route is not defined. Let’s add the new route:

# config/routes.rb
Myapp::Application.routes.draw do
  root to: "posts#index"

Now implement the controller that will serve the /posts route:

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.all

And create the view that will render Posts#index action and list all posts:

<!-- app/views/posts/index.html.erb -->
  <% @posts.each do |post| %>
      <%= post.title %><br />
      <%= post.content %>
  <% end %>

Now run the feature file and you should see it pass:

$ bundle exec cucumber features/home_page.feature

1 scenario (1 passed)
3 steps (3 passed)

Congratulations for making it this far. You should now be fully equipped to work in the BDD cycle and deliver clean, working code.

P.S. Would you like to learn how to build sustainable Rails apps and ship more often? We’ve recently published an ebook covering just that — “Rails Testing Handbook”. Learn more and download a free copy.

Have a comment? Join the discussion on the forum