Feb 03

Date published: 2-3-2014

Rails version: 4.0.0

RSpec

In my last tutorial I demonstrated how to setup tests for a model using the testing framework included with Rails. In this tutorial, I want to try out a different testing framework called RSpec to see how it compares to what we did before. RSpec is one of the most popular ways to test Rails apps, so if you work with Rails, you’re bound to run into projects that use it for testing.

Create a RSpec branch

We’re going to expand on the project we did last week, which can be found here:

http://github.com/wordplay/rails_model_testing_example

Open the terminal window and navigate to the directory of the project. We don’t want to overwrite what we’ve already done because when we get done learning about RSpec, we may decide we don’t like it as much as the Rails tests we did before. This is a perfect example of when you should use a new branch in Git to save your changes. Then when you’re finished, you can decide to either move the changes into the master branch and keep using RSpec or discard the changes entirely. In the terminal, run the following commands:

$ git checkout -b rspec
Switched to a new branch 'rspec'
$ git branch
  master
* rspec

So what did we just do? The checkout command is used to change between branches in our source tree. Using “-b rspec” tells Git to create a new branch with the name rspec before checking it out. The second command tells Git to list all branches and shows we have the master branch and our new branch. The asterisk tells you which branch is currently checked out. When you create a new branch, it will be exactly the same as the branch you were on before, but any changes in this new branch won’t be propagated back to the master branch unless you merge them yourself. It’s a good way idea to use a new branch anytime you want to test out something you’re not sure you’ll want to use.

Install RSpec

Now that we’ve got our branch setup, we need to install RSpec and a few other gems that we’ll be using in our testing. Open the Gemfile and add the following:

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

So what do the gems we added do? rspec-rails is a package that includes everything we need to use RSpec in a rails app. FactoryGirl is a replacement for the fixtures we used in our testing previously. It will allow us to create new objects on the fly. We need to install the gems, and we should make sure RSpec files are installed. Save the Gemfile and switch to the terminal window. Type in the following commands:

$ bundle install
$ rails generate rspec:install

The last thing we need to do to switch over is make sure that we remove all the old files from the previous way we were testing. We also want to reset the database so that data loaded in from fixtures is removed. Run the following commands in the terminal window:

$ git rm -r test/
$ rake db:reset
$ rake db:test:prepare

Rewriting our tests

Just like last time, let’s setup our data generators first. In this case, we need to setup a data factory for the User model. Create a new file named spec/factories/users.rb and fill it in:

FactoryGirl.define do
  factory :user do |f|
    f.username "Adam"
    f.password "Password1"
  end
end

Now we need to rewrite our test file using RSpec. Create a file named spec/models/user_spec.rb and fill it in:

require 'spec_helper'

describe User do

# Test that we can add a valid user
  it "should create a user with valid info"

# Tests for username validation
  it "should not save without username"

  it "should not create a duplicate user"

  it "should not have a too short username"

  it "should not have a too long username"

# Tests for password validation
  it "should not save without password"

  it "should have a robust password"
end

Whereas in the previous example we named everything as a test, RSpec strives to be more human readable and uses the word it to refer back to the model being tested. In this case, it refers to the User model, and the descriptions of the tests are mostly the same. We’ll fill in the tests in just a second, but before that let’s see if RSpec is actually working. In the terminal window, you should see something like the following when you run RSpec:

$ rspec spec/models/
*******

Pending:
  User should have a robust password
    # Not yet implemented
    # ./spec/models/user_spec.rb:20
  User should not save without password
    # Not yet implemented
    # ./spec/models/user_spec.rb:18
  User should not have a too long username
    # Not yet implemented
    # ./spec/models/user_spec.rb:15
  User should not create a duplicate user
    # Not yet implemented
    # ./spec/models/user_spec.rb:11
  User should not have a too short username
    # Not yet implemented
    # ./spec/models/user_spec.rb:13
  User should create a user with valid info
    # Not yet implemented
    # ./spec/models/user_spec.rb:6
  User should not save without username
    # Not yet implemented
    # ./spec/models/user_spec.rb:9

Finished in 0.00098 seconds
7 examples, 0 failures, 7 pending

All of our tests are pending because we haven’t filled anything in for them yet. I’ll fill all of them in here, but I encourage you to go step by step and compare them to our previous tests to understand what’s happening here. Fill in the tests with the following:

require 'spec_helper'

describe User do

# Test that we can add a valid user
  it "should create a user with valid info" do
    FactoryGirl.create(:user).should be_valid
  end

# Tests for username validation
  it "should not save without username" do
    FactoryGirl.build(:user, username: nil).should_not be_valid
  end

  it "should not create a duplicate user" do
    FactoryGirl.create(:user, username: "Adam")
    FactoryGirl.build(:user, username: "Adam").should_not be_valid
    FactoryGirl.build(:user, username: "adam").should_not be_valid
  end

  it "should not have a too short username" do
    FactoryGirl.build(:user, username: "x").should_not be_valid
  end

  it "should not have a too long username" do
    FactoryGirl.build(:user, username: "12345678901234567890").should_not be_valid
  end

# Tests for password validation
  it "should not save without password" do
    FactoryGirl.build(:user, password: nil).should_not be_valid
  end

  it "should have a robust password" do
    FactoryGirl.build(:user, password: "PASSWORD1").should_not be_valid
    FactoryGirl.build(:user, password: "password1").should_not be_valid
    FactoryGirl.build(:user, password: "Password").should_not be_valid
  end
end

As you can see from the code, the RSpec version is a little cleaner than what we wrote using the Rails test framework. The main change is that where we used assertions before, we say that the object we’re creating should or should not be valid. In this small example, it may not make much difference, but for a large project with lots of tests, the compactness and readability of RSpec might make it a better choice.

Let’s switch to the console and save our changes in Git:

$ git add .
$ git commit -m "Replaced tests with RSpec"

Source code for this tutorial can be found at:

http://github.com/wordplay/rails_model_testing_example/tree/rspec

A lot of the information in this tutorial was adapted from another really good tutorial on switching to RSpec. If you want to see a more in-depth example of RSpec, you might want to check it out here:

http://everydayrails.com/2012/03/12/testing-series-intro.html

Leave a Reply

preload preload preload