Will Little Subscribe

How to setup a Rails app for Test-Driven- and Behavior-Driven Development with Rspec and Capybara

Continuing forward in our introduction to web and mobile development tutorial series, here we'll learn how to prep our Rails app to begin writing code in a Test-Driven Development (TDD) and Behavior-Driven Development (BDD) paradigm.

[Author's note: I wrote the first couple dozen tutorials in this series a few years ago and I'm in the process of updating the content to reflect the evolution of best practices in the industry. Please comment if you see anything I missed that should be updated. Thanks!]


If you are just tuning in, you can either quickly scan the previous post to setup a Rails app, clone the app from Github and “git checkout tags/v0.1” to sync to the exact spot I'm writing from here, or you can use your own Rails 4+ app that hasn't yet been TDD/BDD-ified.

Writing Rails code the non-TDD/BDD way, FYI, means you simply plow forward setting up and filling in your models, controllers, views, routes, partials, helpers, JavaScripts, etc. without bothering to test anything in an automated way. You simple write code, refresh the browser, click some stuff maybe, and repeat.

This is all fine and dandy until you start working with other developers, deploy updates to production, and/or revise code you (or someone else) has written before. In other words, if you're attempting to build anything serious then you absolutely need to write code in a TDD/BDD way!!!!


In short, TDD is writing tests first, then writing code in your app to make the tests pass. This way you always have a safety net built and up-to-date so you can sleep better at night when you, or someone else, revises your code.

BDD is essentially the same as TDD, but it writes tests from a “user story” perspective, which helps solves a bunch of common software development problems. The wikipedia article on Behavior-Driven Development is actually quite good and you should give it a quick scan (or thorough read) if you want to dive into more details.

For our purposes here, I'll walk you through how to setup your Rails app for TDD/BDD using RSpec, Capybara, and a sweet Capybara driver calledCapybara-webkit. We'll use Rubygems called factory_girl_rails and faker to help setup our resources in our test environment (these safe us a ton of time, you'll see!).


Ok, first install the Qt libraries on your local machine (to ensure capybara-webkit will install correctly, then open up your Gemfile and add these guys in there:

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

group :test do
  gem 'faker'
  gem 'capybara-webkit'
. . .

Now run “bundle install” in your terminal (from your Rails app root directory) and make sure everything installs correctly. If you run into problems, copy the error message into Google and follow instructions you see from other developers who had the same issue(s).


Open up your database.yml file and make sure your test database configs are good to go. If you've been following along in this tutorial series, then you shouldn't need to change anything here:

<em>#config/database.yml </em>
. . . 
  adapter: postgresql
  encoding: unicode
  database: OurAgendaApp_test
  pool: 5
  username: OurAgendaApp
. . .

If you're just tuning in, you'll want to make sure your adapter, database name, and database user are synced up to your local settings.

From here you'll want to run these commands in your terminal:

$ rake db:create:all
$ rake db:migrate RAILS_ENV=test

Again, if you run into problems, double check your configuration settings and Google any errors you get to find a solution.


Ok, now let's set things up. First, run this to let Rspec setup itself:

$ rails g rspec:install

…and let's open up that spec/rails_helper.rb file and add three important lines:

. . . 
#add this line under the other ones like it up top  
require "capybara/rspec"

#set the default driver 
Capybara.javascript_driver = :webkit
. . .  
RSpec.configure do |config|
  . . .
  #add this line at the bottom of the config section 
  #it saves us time when using FactoryGirl methods. 
  config.include FactoryGirl::Syntax::Methods

Cool. Now let's open up the .rspec file (in the root dir of our app) and add this line to the bottom:

--format documentation

Finally, let's open up our config/application.rb file and add:

module OurAgendaApp
  class Application < Rails::Application
   #add these lines
    config.generators do |g|
      g.stylesheets false
      g.javascripts false
      g.test_framework :rspec,
        :fixtures => true,
        :view_specs => false,
        :helper_specs => false,
        :routing_specs => false,
        :controller_specs => true,
        :request_specs => true
      g.fixture_replacement :factory_girl, :dir => "spec/factories"


In our example app for this tutorial series we'll start with the user model and write a “unit” test for it (i.e. a test for a small unit of our code, which in a Rails context is usually a model — sometimes you'll even here the phrase ‘model test'). If you're writing your own app and following along, you can go ahead and use your own user model or another core model.

Let's start by setting up our user factory. Create a folder within your spec/ folder called “factories” and create a file called “users.rb” in it:

require 'faker'
FactoryGirl.define do
  factory :user do 
    email {Faker::Internet.email}
    password '123'
    password_confirmation '123'

And now let's create our user spec file. Create a another folder within your spec/ folder called “models” and create a file called “user_spec.rb” in it:

require 'rails_helper'
describe User do
 it "has a valid factory" do
 build(:user).should be_valid
 it "is invalid without an email" do
  build(:user, email: nil).should_not be_valid

FYI, as you add more controllers and models to your app, stub files for testing will be automatically created for you (this is what our configuration lines above took care of for us).


In your terminal, go ahead and run your tests:

$ rspec

You should see output indicating that your user unit has a valid factory but does NOT pass the “is invalid without an email” test. You'll get specific output about where your test failed, and what you need to do to fix it.

Ok cool, welcome to Test-Driven Development. Now let's go write code to make sure our user model “is invalid without an email.” How do we do that? Add a validation in our model file, of course!

class User < ActiveRecord::Base
  . . .
  validates :email, presence: true 
  . . .  

Now run “rspec” in your terminal again and you should see both tests pass.

Congrats! Now before you write any more code in your app, it's time to go write a bunch of tests.


For those following along in our tutorial series, now is the time to fill out the unit tests for our Action Items, Agenda Items, Meetings, and Comments. I'll let you take it from here. You can read more about the Domain Specific Language (DSL) for Capybara here to learn about all the cool things you can do with it to test your app. For those following along with their own apps, you should fill out your unit tests now. Don't go too crazy, some tests like it “is invalid without a first name” and such may not be necessary to write (i.e. if they are super obvious).

In future posts in this series, we'll write “feature” tests (which are staples of BDD. That is, end-to-end tests that are related to ‘integration', ‘functional', and ‘acceptance' tests. This post does a great job explaining the nuances and relationships between them.)

- — -

In the next post in this series we will begin the process of merging in cutups (i.e. HTML, CSS, and JavaScript files). Previous post: How to design and prep a Ruby on Rails model architecture.