Would you like to learn how to write tests for your Ruby applications using RSpec?
Then you’re in the right place!
In this tutorial I’ll show you how to do that.
Contents
Why Should You Write Tests?
Here’s why:
It builds a safety net against errors (especially useful for refactoring)
If you don’t have a test suite then you don’t want to touch your code, because of the fear of something breaking…
…having tests increases your confidence!
It helps document your code
Your tests describe what your application should be doing.
It gives you a feedback loop
When you are doing TDD you get a feedback loop that tells you what to focus on next, useful if you get distracted easily.
It helps you make sure your code is producing the results you expect
This one is important!
If you are writing some complex logic, then you want to make sure it’s working with many different inputs & not just with one example you came up with.
Tests can help you uncover corner cases & document them.
It helps you land a Ruby job
Most job applications will appreciate your testing skills, increasing your chances of landing the job.
Getting Started With RSpec
To understand how RSpec works let’s go over an example step-by-step.
We are going to write a simple application that finds factorial numbers.
The first step:
require 'rspec/autorun'
describe Factorial do
# ...
end
This is the initial code for writing your first RSpec test.
The let! method is non-lazy, so the object will be created before any tests are run.
How to Use The Subject Method
Another version of let is subject.
The only difference is that you can only have one subject, and it’s meant to be an instance of the main object you are testing.
RSpec already creates a default subject like this:
subject { Factorial.new }
This is called the “implicit subject”.
You can use it like this:
describe Factorial do
it "finds the factorial of 5" do
expect(subject.factorial_of(5)).to eq(120)
end
end
You can give your subject a name:
subject(:calculator) { Factorial.new }
This behaves the same way as using let, but it enables the use of one-line expectations:
it { should be_empty }
How to Run Code Before All Your Tests
RSpec has execution hooks you can use to run something before & after every test, or a whole group of tests.
For example:
describe Shop do
before(:all) { Shop.prepare_database }
after (:all) { Shop.cleanup_database }
end
If you want to run this code for each example (example = test in RSpec) you can use :each instead of :all.
How To Create Testing Subgroups
If you’re testing different scenarios in your app then it may be helpful to group related tests together.
You can do this using a context block in RSpec.
Here’s an example:
describe Course do
context "when user is logged in" do
it "displays the course lessons" do
end
it "displays the course description" do
end
end
context "when user it NOT logged in" do
it "redirects to login page" do
end
it "it shows a message" do
end
end
end
How to Temporarily Disable a Test
It’s possible to disable a test for debugging purposes.
All you have to do is to change it to xit for the tests you want to disable.
Example:
xit "eats lots of bacon" do
end
Don’t forget to remove the x when you are done!
Running Examples By Name
Instead of disabling tests, you can filter the tests you want to run with the -e flag.
Example:
> ruby person.rb -e bacon
This filtering is based on the test name, so the above example will match any test with the word “bacon” on it.
RSpec Expectations & Matchers
You may remember this example we have been using:
expect(calculator.factorial_of(5)).to eq(120)
But what is this eq(120) part?
Well, 120 is the value we are expecting…
…and eq is what we call a matcher.
Matchers are how RSpec compares the output of your method with your expected value.
In the case of eq, RSpec uses the == operator (read more about Ruby operators).
But there are other matchers you can use.
For example, the be_something matcher:
expect(nil).to be_nil
Where something is a predicate method (like empty?) that is going to be called on the test results.
The default RSpec output is in the “progress” format.
With this format you see dots (.) representing 1 passing test each, an F for a failed test (expected & actual don’t match), or an E for an error.
But there are alternative formatting options you can use.
Here’s a list:
progress
documentation
json
html
You can enable them with the -f flag:
> ruby factorial.rb -f d
Person
eats lots of healthy food
writes many articles
Finished in 0.00154 seconds (files took 0.09898 seconds to load)
2 examples, 0 failures
The documentation format uses your test descriptions to generate the output.
How to Find Slow Tests
RSpec comes with a very handy option to profile your tests.
Just by passing the --profile flag you’ll be able to see how long each test takes to run & fix the really slow ones.
Here’s an example:
> ruby factorial.rb --profile
Factorial finds the factorial of 5
0.00043 seconds
RSpec Video Tutorial
Summary
You have learned how to write tests using the RSpec testing framework.
Now it’s your turn to start writing your own test!