Testing Rails apps with RSpec: Part I
In this two-part series, I’ll cover testing a Rails application—from how to get set up with the latest toolchain, to writing those first tests.
In Part 1, I’ll look at how to set up and configure RSpec 3 (with Factory Girl and Capybara) for a Rails 4 app, and how to generate and run your first specs. Next time, in Part 2, we’ll look at writing model, controller and feature specs.
But first, why write tests?
I was initially very wary of unit-testing. While I knew that I needed to make sure the app worked, I was skeptical of the time tradeoff. The first few tests can seem like more trouble than they’re worth, and quite honestly, those first few probably are more trouble than they’re worth. But after a while, writing tests becomes second nature. I think it can easily take less time to write automated tests than to manually test every feature before every release.
It’s no silver bullet. There will probably still be bugs from scenarios you never thought to test. But even if they can’t catch every bug, tests provide you with confidence that your app works as intended on a basic level. This is all the more important if you didn’t write the app to begin with, or if you’re part of a big team—you won’t always know what effects your changes might have. There might be features you don’t even know about. Ultimately, a solid test suite means less to worry about for you, the developer, and with any luck, a more stable product for the user.
Testing a Rails 4 app with RSpec 3
I really like RSpec. If you’re more of a minimalist, you can always skip the extra gems and use the built-in minitest, but I like the additional features and clean DSL that RSpec provides. For example, to test that a variable is nil:
It’s a matter of taste, but I prefer RSpec’s more human-readable style. Here, we’ll use RSpec 3.0, which landed back in May, and brings a few new changes into the fold (See here for more info: Notable Changes in RSpec 3).
In addition to RSpec, we’ll also set up Factory Girl as a fixture replacement, Capybara for browser-level acceptance (a.k.a. integration) tests, and Database Cleaner for cleaning up between test scenarios.
When you write tests, you’ll need test data. As a fixture replacement, Factory Girl helps you build instances of your models for use in test scenarios. This is accomplished through factories in which you define how to build the instances. Although it’s nothing you couldn’t do yourself with plain old ActiveRecord methods and some helper methods, Factory Girl provides a nice system for setting defaults (and then overriding them) that keeps a lot of boilerplate out of your code.
Acceptance tests look at how the system as a whole functions. For a Rails app, that usually means typing and clicking on things in a web browser and seeing some sort of response. Capybara provides one DSL for automating various browsers to simulate user interactions with your app, which you can then make expectations about using RSpec. Because it provides a single interface to various browsers, it gives you the freedom to do things like use Selenium to run certain tests while using headless webkit to run others.
database_cleaner gem to adjust the way the database cleanup is done. (See this post for more details.)
Configure your Gemfile
Let’s get started. Assuming you’re working inside a new Rails 4 app, add the following to your
Gemfile and then
group :development, :test do gem 'rspec-rails', '~> 3.0.0' gem 'factory_girl_rails' gem 'capybara' gem 'database_cleaner' end
Next, run the RSpec generator to create the initial skeleton:
rails generate rspec:install
To make Capybara available from within RSpec specs, add the following line to
Your Capybara feature specs will also need a home, add the
Next, make the following adjustments to
spec/rails_helper.rb to integrate the
RSpec.configure do |config| config.before(:suite) do DatabaseCleaner.clean_with(:truncation) end config.before(:each) do DatabaseCleaner.strategy = :transaction end config.before(:each, :js => true) do DatabaseCleaner.strategy = :truncation end config.before(:each) do DatabaseCleaner.start end config.after(:each) do DatabaseCleaner.clean end end
By default, RSpec generates a
.rspec file in your app’s root. This allows you to set different command line options (see
rspec -h) that will be automatically picked up. The default
.rspec includes the
--warnings option, which can be really noisy even in a brand new Rails app. If you see a lot of warnings later on, you can hide them by removing this line.
The next time you run
rails generate resource, Rails should already be configured to generate specs under
spec/ and factories under
Let’s try that out with the proverbial Rails blog example:
rails generate resource post title:string content:text published:boolean
If everything’s correctly configured, you should see something close to this:
Note the factory at
spec/factories/posts.rb, the model spec at
specs/models/post_spec.rb, and the controller spec at
With the new specs in place, try running
rspec (you can also run
rake), to see the results. So far, you should only see a few pending specs:
** Pending: PostsHelper add some examples to (or delete) ./spec/helpers/posts_helper_spec.rb # Not yet implemented # ./spec/helpers/posts_helper_spec.rb:14 Post add some examples to (or delete) ./spec/models/post_spec.rb # Not yet implemented # ./spec/models/post_spec.rb:4
Now that everything is set up, we’re ready to write some tests. Stay tuned for Part 2. In the meantime, here are a few more resources worth a read:
- A Guide to Testing Rails Application — the Rails Guide to testing
- Thoughbot’s How We Test Rails Applications
- DHH’s TDD is dead. Long live testing.