One of the purposes of writing tests is to provide living documentation of application’s code. Tests provide real examples of how a certain class or function is supposed to be used. Tests could also document the exact dependencies of the tested code.
When Rails boots it loads most, if not all, of the application’s code, along with all of the dependencies (gems). Because of this, there is no need to require dependencies in individual files that contain application logic. When looking at the source of a specific class, it is hard to tell what external code it depends on. The test doesn’t help either.
A typical RSpec test usually looks something like this:
require 'spec_helper' describe StyleGuide do # actual tests omitted end
In the Rails community, it has become a de facto standard to require the default
spec_helper (or an equivalent) in each test file. A typical
spec/spec_helper.rb file ends up loading the whole Rails environment,
requiring numerous helper files, and setting up various configuration options.
All of that, en masse, is more than what any particular test file needs.
Certainly, integration and feature tests depend on the entire Rails environment.
ActiveRecord model tests depend on the presence and configuration of a database.
These are all good use cases for
spec_helper. But what about unit tests that
don’t require the database? When testing a plain old Ruby class, there might
only be a few dependencies, if any.
The Solution: RSpec 3.x
RSpec 3.x introduces a new
which contains all the Rails-specific spec configuration and leaves
spec_helper.rb minimal, with no Rails code.
Here’s an example
Here’s an example
require "webmock/rspec" RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.syntax = :expect end config.mock_with :rspec do |mocks| mocks.syntax = :expect end config.order = :random end WebMock.disable_net_connect!(allow_localhost: true)
Using the minimal
Being conscious about what must be required for a particular source file is a good thing. Instead of loading everything but the kitchen sink, let’s specify the minimum dependencies inside of the test.
Here’s a revision of our code from above:
require 'rubocop' require 'app/models/style_guide' describe StyleGuide do # actual tests omitted end
This code states exactly what the tested class (
depends on: the gem
rubocop and the model
Note that we don’t need to require
spec_helper manually in
rails_helper or in our
It is required for us in
.rspec by default:
--color --warnings --require spec_helper
The idea behind
spec_helper is to keep it minimal and
resist the urge to add things to it.
It should avoid becoming a junk drawer.
Tests which might be part of a Rails application test suite, but don’t actually depend on Rails or ActiveRecord can now require this basic spec helper along with the essential gems and files.
Each test now explicitly documents dependencies of the tested code. Loading minimal dependencies during tests removes any magical coupling, helps with refactoring, saves time during debugging, and makes tests run faster.
Want to learn more techniques about decoupling code away from Rails?