Updated

This post is a mush of various blog posts, tutorials and answers in stackoverflow, of how to set up and test a rails application using Rspec, Capybara and FactoryGirl.

What I have done is glue together the information in a meaningful way to help me and others (probably ;)) quickly grasp the methodology and terminology used.

I have tried to be as accurate as possible with the sources of my research. If you think there is an error or I’ve made a wrong copy paste somewhere please comment.

I will try to keep this article up to date, with new information as my research progress.

Keep in mind that this post is a work in progress. Please feel free to contact me with any corrections, requests or suggestions.

How to install rspec

Ok, enough with all the intro, lets start by installing the necessary gems.

Add in your app’s Gemfile

gem 'rspec-rails'
gem 'capybara'
gem 'launchy'
gem 'factory_girl_rails'
gem 'email_spec'

Install RSpec and prepare database

bundle exec rails g rspec:install
#      create  .rspec
#       exist  spec
#      create  spec/spec_helper.rb

bundle exec rake db:test:prepare

The email_spec gem provides a collection of RSpec matchers for testing email.

Add to spec/spec_helper.rb file the following to enable the email_spec library

# spec/spec_helper.rb
require 'email_spec'

RSpec.configure do |config|

# Start: Add this block
  config.include(EmailSpec::Helpers)
  config.include(EmailSpec::Matchers)
# Stop: Add this block

end

To reset your application database to a pristine state during testing, you can use Database Cleaner.

Add to spec/spec_helper.rb

RSpec.configure do |config|
  config.include(EmailSpec::Helpers)
  config.include(EmailSpec::Matchers)

# Start: Add this block
  config.before(:suite) do
    begin
      DatabaseCleaner.start
    ensure
      DatabaseCleaner.clean
    end
  end
# Stop: Add this block
end

Configure the Rails Generator

By default the Rails generator rails g ... will create placeholder files for Test::Unit.

Modify the config/application.rb configuration settings to indicate we are using RSpec.

We’re using scenarios (integration tests) so unit tests of helpers and views are redundant. We’ll tell the Rails generator to skip unit tests for helpers and views.

Rails also likes to create controller-specific helper classes, JavaScript files and stylesheet stubs. If you are like most developers, you will create these files manually as you need them, so this is a good time to tell the generator to skip the clutter.

# config/application.rb
require File.expand_path('../boot', __FILE__)

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env)

module MyApplicationName
  class Application < Rails::Application

        # Start: Add this block
        config.generators do |g|
            g.test_framework :rspec, :fixture => true
            g.fixture_replacement :factory_girl, :dir => "spec/factories"
            g.view_specs false
            g.helpers_spec false
            g.stylesheets = false
            g.javascripts = false
            g.helper = false
        end
        # Stop: Add this block

    end
end

Transactions

Source

When you run rails generate rspec:install, the spec/spec_helper.rb file includes the following configuration

RSpec.configure do |config|
  config.use_transactional_fixtures = true
end

What it really means in Rails is run every test method within a transaction. In the context of rspec-rails, it means run every example within a transaction.

The idea is to start each example with a clean database, create whatever data is necessary for that example, and then remove that data by simply rolling back the transaction at the end of the example.

Since we’re doing our own db cleaning, just turned it off:

config.use_transactional_fixtures = false

Running a specific spec

Define some spec

describe "Something" do
  it "does stuff" do
    # Check if it does stuff
  end
 
  it "does other stuff" do
    # Check if it does other stuff
  end
 
  it "does one more thing" do
    # Check if it does one more thing
  end
end

Then we can execute it by line number or spec name

# Using line numner
rspec spec/something_spec.rb:6 

# Using spec name
rspec spec/something_spec.rb -e "does other stuff"

Formatters

Progress (default)

rspec --colour spec/

Documentation

rspec --colour -f doc spec/
# Stack
#   when new
#     should be empty
#     should have 0 items

Html documentation

rspec --colour -f html -o specs.html spec/

Configuration

We don’t want to type, i.e. --colour or -f html every time!

Put common options in .rspec in the project root.

# .rspec
--colour
-f html

RSpec 101 (Contexts)

describe "Rain" do
  context "in the summer" do
    it "is refreshing" do
      ...
    end
  end
 
  context "in the winter" do
    it "is unpleasant" do
      ...
    end
  end
end

context is an alias for describe

The argument to describe becomes the subject

describe 42 do
  it { should be_even }
  it { should_not be_zero }
end

If it’s a class, the subject is a new instance

describe Array do
  it { should be_empty }
  it { should have(0).items }
end

Access attributes of the subject with its

describe [1, 2, 3, 3] do
  its(:size) { should == 4 }
  its("uniq.size") { should == 3 }
end

You can set the subject explicitly using a block:

describe "An array containing 1, 2, 3, 3" do
  subject { [1, 2, 3, 3] }
 
  its(:size) { should == 4 }
end

And access it in examples as subject:

describe Array do
  it "is empty" do
    subject.should be_empty
  end
end

More [1] (check references at bottom)


Built-in matchers

a.should equal(b) # both pass if a.equal? b
a.should be(b)    #
 
a.should eql(b)   # passes if a.eql? b
 
a.should == b     # both pass if a == b
a.should eq(b)    #

Math::PI.should be_within(0.01).of(22.0/7)

obj.should be_true  # passes if obj is truthy (not nil or false)
obj.should be_false # passes if obj is falsy (nil or false)
obj.should be_nil   # passes if obj is nil
obj.should be       # passes if obj is not nil


7.should == 7
[1, 2, 3].should == [1, 2, 3]
"this is a string".should =~ /^this/
"this is a string".should_not =~ /^that/
String.should === "this is a string"

# Comparison operators work with the "be" matcher:
37.should be < 100
37.should be <= 38
37.should be >= 2
37.should be > 7

Capybara feature spec

Source

A new type of spec–the feature spec–has been created for use with Capybara 2. Create a new folder features inside spec folder

/spec
|- controllers
|- views
|- routing
|- requests
|- helpers
|- decorators
|- models
|- factories
|- *features*

Feature specs require the capybara gem, version 2.0.0 or later.

The feature and scenario DSL correspond to describe and it, respectively. These methods are simply aliases that allow feature specs to read more as customer tests and acceptance tests.

# Specify creating a Widget by driving the application with capybara https://www.relishapp.com/rspec/rspec-rails/docs/feature-specs/feature-spec
require "spec_helper"

feature "Widget management" do
  scenario "User creates a new widget" do
    visit "/widgets/new"

    fill_in "Name", :with => "My Widget"
    click_button "Create Widget"

    expect(page).to have_text("Widget was successfully created.")
  end
end

Difference between stub and mock

Sean Copenhaver http://stackoverflow.com/questions/3459287/whats-the-difference-between-a-mock-stub

I believe the biggest distinction is that a stub you have already written with predetermined behavior. So you would have a class that implements the dependency (abstract class or interface most likely) you are faking for testing purposes and the methods would just be stubbed out with set responses. They wouldn’t do anything fancy and you would have already written the stubbed code for it outside of your test.

A mock is something that as part of your test you have to setup with your expectations. A mock is not setup in a predetermined way so you have code that does it in your test. Mocks in a way are determined at runtime since the code that sets the expectations has to run before they do anything.

Tests written with mocks usually follow an initialize -> set expectations -> exercise -> verify pattern to testing. While the pre-written stub would follow an initialize -> exercise -> verify. The purpose of both is to eliminate testing all the dependencies of a class or function so your tests are more focused and simpler in what they are trying to prove.

or

James Mead http://jamesmead.org/blog/2006-09-11-the-difference-between-mocks-and-stubs

Stubbing a method is all about replacing the method with code that returns a specified result (or perhaps raises a specified exception). Mocking a method is all about asserting that a method has been called (perhaps with particular parameters).

If you think about it, it’s difficult (or impossible?) to do mocking without stubbing – you need to return from the mocked method, so that the code under test can complete execution. So mocking libraries tend to implicitly or explicitly allow you to do stubbing.

or

Martin Fowler - Mocks Aren’t Stubs

The vocabulary for talking about this soon gets messy - all sorts of words are used: stub, mock, fake, dummy. For this article I’m going to follow the vocabulary of Gerard Meszaros’s book. It’s not what everyone uses, but I think it’s a good vocabulary and since it’s my essay I get to pick which words to use.

Meszaros uses the term Test Double as the generic term for any kind of pretend object used in place of a real object for testing purposes. The name comes from the notion of a Stunt Double in movies. (One of his aims was to avoid using any name that was already widely used.) Meszaros then defined four particular kinds of double:

Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it ‘sent’, or maybe only how many messages it ‘sent’.

Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Of these kinds of doubles, only mocks insist upon behavior verification. The other doubles can, and usually do, use state verification. Mocks actually do behave like other doubles during the exercise phase, as they need to make the SUT believe it’s talking with its real collaborators - but mocks differ in the setup and the verification phases.

Also see [2] below.


A controller spec is broken down by controller method—each example is based off of a single action and, optionally, any params passed to it. Here’s a simple example:

it "redirects to the home page upon save" do
    post :create, contact: Factory.attributes_for(:contact)
    response.should redirect_to root_url
end

The description of the example is written in explicit, active language. The example only expects one thing: After the post request is processed, a redirect should be returned to the browser. A factory generates test data to pass to the controller method; note the use of Factory Girl’s attributes_for option, which generates a hash of values as opposed to a Ruby object.

However, there are also a couple of new things to look at:

The basic syntax of a controller spec—it’s REST method (post), controller method (:create), and, optionally, parameters being passed to the method.

The aforementioned attributes_for call to Factory Girl—not rocket science, but worth mentioning again because I had a habit early on of forgetting to use it versus default factories.


How to generate rspec files in Rails

bundle exec rails g rspec:scaffold user

will execute

create  spec/controllers/users_controller_spec.rb
create  spec/views/users/edit.html.erb_spec.rb
create  spec/views/users/index.html.erb_spec.rb
create  spec/views/users/new.html.erb_spec.rb
create  spec/views/users/show.html.erb_spec.rb
invoke  helper
create    spec/helpers/users_helper_spec.rb
create  spec/routing/users_routing_spec.rb
invoke  rspec
create    spec/requests/users_spec.rb

https://github.com/thoughtbot/factory_girl/issues/385

Add paperclip attachment in FactoryGirl

Okay so it looks like my project isn’t loading the test_helper.rb because when I change the code to the following it will work

include ActionDispatch::TestProcess
FactoryGirl.define do
    factory :mongo_document do 
      original_filename "test.jpg"
      file { fixture_file_upload(Rails.root.to_s + '/spec/fixtures/files/test.jpg', 'img/jpeg') }
  end
end

What happens when Capybara is running with js: true

Source

When Capybara runs under rack-test, everything happens in the same thread of the same process. Capybara runs your stuff directly agains your Rails app. What this means is that if you open a transaction in cucumber, that same transaction is used within your Rails app, so if you create a database record in Cucumber, it will show up in your Rails app.

What happens under Selenium is this: Capybara starts up your Rails app using a webserver (usually webrick or thin) in a separate thread of the same process. ActiveRecord assumes that different threads are used to handle concurrent requests, so it uses separate connections, and thus separate transactions for each thread. What this means is that if a record is created in Cucumber, that record is created in a different transaction than the Rails app is running under, which means it won’t show up in the app.

This leaves us with three possible solutions:

  1. Switch off transactions entirely, truncate (empty out) the database after each test
  2. Switch off transactions only for those tests that use Selenium, truncate the DB after those.
  3. Make sure transactions are switched on and force Rails to use the same transaction for all threads

If you just set up DatabaseCleaner with :truncation mode, number 1 will happen. This should do the job, but it’s pretty slow. Also transactions are nice, since there’s less risk of crap data remaining in your DB.

Number 2 is what cucumber does out of the box. It works, but it’s kind of convoluted, and has a tendency to break every now and then.

Number 3 is what José’s hack is all about. The consequence of this, is that if you use 3, transactions need to be switched on. You do not need DatabaseCleaner for that, just set:

Cucumber::Rails::World.use_transactional_fixtures = true

Access a modal window with Capybara

Source

How do you click on buttons in modal confirmation dialogues

Create a file capybara.rb in support folder and add

# spec/suport/capybara.rb
Capybara.javascript_driver = :selenium

Then in a test file

describe "upon accepting warning", js: true do
    it "should do something" do
      visit some_path
      click_button('save')

      a = page.driver.browser.switch_to.alert
      a.accept  # can also be a.dismiss
      page.should have_content("some text")
    end
end

You can also test the text of the dialog with

a = page.driver.browser.switch_to.alert
a.text.should eq("Some special alert dialog text")
a.accept

You HAVE to call accept or dismiss on the alert or Selenium will give you that error

Selenium::WebDriver::Error::UnhandledAlertError

Forms

If the submit button of a form is outside the form definition (past the </form> tag) the form id MUST be the same with submit button form attribute, since it specifies one or more forms the button belongs to,

<form id="create_my_entity">
...
</form>

<button form="create_my_entity">
...
</button>

References

[1] Rspec Presentation by Kerry Buckley

[2] Testing Delayed Jobs

[3] Test doubles in theory