RSpec is a Rails gem designed to make it easy to write unit and feature tests. If you run into any trouble, you can read the docs here
Throughout my career and especially while job-hunting, the number one piece of advice I was given was to write unit tests.
In any given situation, be it a take-home exam or a portfolio piece, if you write tests it will show that you're a thoughtful engineer who takes time to think through problems.
And your code will be better for it.
In this article we'll talk through how you can get RSpec running, the basics of writing your first unit tests, and some nifty features in RSpec to help keep your tests clean and organized.
Let's dive in:
Installing RSpec
Before you can start writing tests with RSpec, you'll need to install the gem and set up your Rails application. To get started, follow these steps:
- Open your
Gemfile
and add therspec-rails
gem to the development and test group:
group :development, :test do
gem 'rspec-rails', '~> 5.0'
end
Install the gem by running
bundle install
Run the RSpec generator with
rails generate rspec:install
. This command creates a.rspec
file, aspec
folder, and aspec_helper.rb
file in your project directory.
After this is configured, you're ready to write your first unit test!
Writing our first tests
With RSpec installed, let's create a simple model and write a unit test to ensure it's working correctly.
For this example, we'll create a
User
model with aname
attribute. Runrails generate model User name:string
to generate the necessary files. You'll have to run a migration for this change to be added to your database.Add the following code to our model to validate the presence of a
name
field:class User < ApplicationRecord validates :name, presence: true end
Note that in the
spec
folder, a new folder calledmodels
, and inside it, a file nameduser_spec.rb
has been generated. This is where we'll write our tests for the User model.Open
user_spec.rb
and start by creating a newdescribe
block for the User model and write a simple test to check if a user with a valid name can be createdRSpec.describe User do it 'is valid with a name' do user = User.new(name: 'John Doe') expect(user).to be_valid end it 'is not valid without a name' do user = User.new expect(user).to_not be_valid end end
- To execute your test, run
bundle exec rspec
in your terminal. If everything is set up correctly, you should see an output indicating that the test passed.
- To execute your test, run
You can now write additional tests for your User model or any other part of your application by following the same pattern within the spec
folder.
Extra features
While none of these are necessary to function, RSpec does have a whole host of cool features that help promote clean and organized unit tests.
It's easy for these files to get long and unwieldy, so keeping your codebase clean and DRY will demonstrate expertise.
Below, I'll detail each of RSpec's interesting features that we use regularly in our day-to-day development work, as well as a code example to demonstrate what I mean.
Context blocks
The context
method helps create logical groups for your tests based on specific conditions or scenarios.
This can make your tests more readable and better organized.
RSpec.describe User do
context 'when name is present' do
let(:user) { User.new(name: 'John Doe') }
it 'is valid' do
expect(user).to be_valid
end
end
context 'when name is not present' do
let(:user) { User.new }
it 'is not valid' do
expect(user).to_not be_valid
end
end
end
Shared examples
RSpec allows you to define reusable examples that can be included in multiple test groups, helping you keep your tests DRY.
shared_examples 'a valid user' do
it 'is valid' do
expect(user).to be_valid
end
end
describe AdminUser do
let(:user) { AdminUser.new(name: 'John Doe') }
it_behaves_like 'a valid user'
end
describe RegularUser do
let(:user) { RegularUser.new(name: 'Jane Doe') }
it_behaves_like 'a valid user'
end
Custom matchers
RSpec allows you to create custom matchers that make your tests more expressive and readable.
RSpec::Matchers.define :be_a_valid_user do
match do |user|
user.valid?
end
end
describe User do
let(:user) { User.new(name: 'John Doe') }
it 'is valid with a name' do
expect(user).to be_a_valid_user
end
end
Final thoughts
As someone who's been involved both in interviewing and in hiring, I've seen that one of the top ways a candidate can stay out is by writing a suite of thoughtful unit tests.
It's an immediate signal to the hiring team that you're a professional and you know what you're doing.
Use this post as a reference and write some tests!
Thanks for reading
Austin