Testing with RSpec
Testing in any language is pretty much one of the most vital parts of development. Without it, applications become fragile, breaking whenever you try to add a new feature. So today we’ll take a look at the basics of RSpec and TDD (test-driven development).
Setting up
Let’s build a tiny standalone project:
mkdir rspec_tutorial
cd rspec_tutorial
bundle init
bundle add rspec
bundle exec rspec --init
That last command creates a spec/ folder and an .rspec file - the conventional layout you’ll see in every Ruby project.
Write the test first
We’re going to test a Dog class with a #bark method that returns "Woof!". Important: none of that code exists yet. In TDD we write the test first.
Create spec/dog_spec.rb:
require_relative "../dog"
RSpec.describe Dog do
describe "#bark" do
it 'returns the string "Woof!"' do
expect(subject.bark).to eql("Woof!")
end
end
end
Breaking that down: RSpec.describe Dog scopes the tests to our class, the inner describe "#bark" scopes to the method, it describes the behaviour in plain English, and expect(...).to eql(...) is the actual assertion. subject is a freebie - RSpec instantiates Dog.new for you.
Run it:
bundle exec rspec
It fails, because there’s no Dog yet.
Make it pass
Create dog.rb in the project root - and let’s deliberately get it wrong first:
class Dog
def bark
"Meow!"
end
end
expected: "Woof!"
got: "Meow!"
A failing test that tells you exactly what’s wrong - that’s the whole point. Fix the string to "Woof!", run bundle exec rspec again, and enjoy the green dot.
In a Rails app
For Rails, use rspec-rails (version 8 as of writing):
# Gemfile
group :development, :test do
gem "rspec-rails"
end
bundle install
bin/rails generate rspec:install
Same concepts, plus model specs, request specs and system specs to grow into. Red, green, refactor - repeat forever.