Rails unit-testing best practices

Picture of Jean-Philippe Boily
Jean-Philippe Boily, Monday July 28, 2014

At Rainforest, we love testing as it is the best way to ship high quality software. In addition to using Rainforest tests, we use a bunch of testing tools for our Rails applications. In this Deployment Academy post, I'll share the core elements of that toolset.


Let's start with the core tool in our testing: RSpec. I loved RSpec the minute I discovered it years ago. It has a really nice syntax that is easy to pick up and really clear to read. Yes, it's not the only option (e.g. minitest which ships with Ruby). This is almost a religion to some people, but we love RSpec.

Here is what an RSpec test can look like:

```ruby describe Client do let(:client) { create(:client) }

describe '#active?' do context "when the client is active" do it { expect(client.active?).to be_true } end

context "when the client is inactive" do
  let(:client) { create(:client, :inactive) }

  it { expect(client.active?).to be_false }

end end ```

Isn't that nice and clear? I love it!

Factory Girl

This is the create(:client, :inactive) part of the previous example. It is a great tool to create fake data for your tests. Some people will prefer fixtures, but we prefer to actually hit the database because we find it to be more reliable.

Factory Girl has a nice, descriptive way of declaring factories:

```ruby FactoryGirl.define do factory :client do name "John Doe" state "active"

trait :inactive do
  state "inactive"

end end ```

Database Cleaner

What happens with all that fake data you ask me? There are a few possibilities but what we prefer is using the Database Cleaner gem. It gives you different options in terms of cleaning the database before each test. Different strategies are available but we use transactions, it's just rolled back and never committed.

I want my results, NOW!

Those tools are all great, right? But that's not all! To be really efficient, you want to have feedback as fast as possible. You want to know if your tests and your code are working or not.

I have found that the following combo is really efficient:

Guard and guard-rspec

The first one, Guard, will watch your files and do stuff whenever they change. With guard-rspec, it will run the RSpec specs related to the file you changed, and only those. Not enough for you? If you had failed tests on the previous save, it will run only the failed specs the next time, until it's green. You can even have guard-rspec kick off the whole suite if you want after having fixed your specs, but I personally prefer to kick off full runs "manually" by pressing enter in the Guard terminal.

Spring or Zeus

These make sure your full Rails environment doesn't get reloaded before every run. That's a MAJOR bump in efficiency. If you try just one tool, it's one of these!

Spring is now enabled by default in new Rails projects (4.1+), but you can add it to your current project easily. Zeus is built in Go and has been around for a little while now. They both serve the same purpose: making sure you don't have to wait long for your tests to run.


The last one that will make you faster is terminal-notifier-guard. The name is descriptive, but let me explain: this will display your test results in a nice OSX notification like this:

RSpec results in OSX notifications

Other tools we love and use that you should look at

Some of those will be covered in future Deployment Academy posts, but you can look at them in the meantime:

  • shoulda-matchers: Collection of testing matchers.
  • VCR: This is great if your tool is hitting some external API. It records your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.
  • Jasmine: Jasmine is a behavior-driven development framework for testing JavaScript code. Its syntax looks a bit like RSpec, especially if you use CoffeeScript.
  • guard-jasmine: This a lot like guard-rspec, this will run your Jasmine specs on save.


Ruby and Rails' ecosystems are very rich in testing tools, and after much iteration these are the ones we love and cherish. What tools are you using that you like a lot?

Thanks for reading!