Hermetic Testing with Rspec - Part 1

"Hermetic" testing means that the test code itself contains all of the setup information (and teardown actions) needed for the test to run. In other words, the test describes itself.

In Rails-Rspec, this means we use transactional fixtures and we don't use a truncation strategy.

In Rspec, each test is written in code with an "it" block.

What's important about transactional fixtures is that every test has its own data setup. Before each "it" block (a block of code that describes 1 test), your setup will run in a database transaction.

This makes the database behave as-if the data is 'frozen in place' without actually being committed to to the underlying database mechanism (Postgres, MySQL, etc).

The advantage to this style of testing (transactional fixtures) is that each test can rollback the transaction and reset the database to its original state, and it can do this very quickly.

The downside to this style of testing is that our hermetic tests often need a little trickery to DRY up your testing style. (Don't-Repeat Yourself). Alternatively, your Rspec tests come out with repetitive setup code.

Either way, the primary tools this tutorial will teach you are:

• Rspec

• Factory Bot

• FFaker

Rspec is the primary way that tests, called "specs," are written. Factory Bot is used to define a basic sample of data for our objects. These object will map to ActiveRecord objects.

1/ Install Rspec + Factory Bot

Add to Gemfile in a group marked :development and :test. Be sure to add it to a group for both :development and :test (do not add it to only a :test group).

gem 'rspec-rails'

gem 'factory_bot_rails'

then run bundle install

Run the rspec installer with

rails generate rspec:install

Now, notice that these files are created

      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb

Now delete your test/ folder with

rm -rf test/

(This removes the default folder for Minitest, which is the alternative to Rspec that we are not covering in this tutorial.)

Check-in this code using Git and give it a commit message of something like "installs Rspec"

2/ Meet spec_helper and rails_helper

For historical reasons, Rails-Rspec apps come with two default files: spec_helper and rails_helper.

All Rspec specs must begin with this exact line:

require "rails_helper"

When you run any rspec test, it runs as-if the working directory is the spec/ folder itself, even when you are running a spec nested several folders deep. So all Rspec specs you write, including ones nested several folders deep, must begin with this exact line:

require "rails_helper"

Both files contain Rspec configuration, but rails_helper contains configuration specific to Rails. Let's take a look a the default spec/rails_helper.rb file now.

First take note this is where RAILS_ENV is set to test. The ||= Ruby operator is called null coalescence and it means that if the RAILS_ENV is not set in the environment (ENV global variable), then set it here.

Then we explicitly load any settings specific to the test environment itself. (These are found in config/environment/test.rb)

Pay attention to what this comment says: Rspec looks for any file inside of the the spec/ directory that ends with _spec.rb. Those files will automatically be seen as spec files, but other files will not. If you can't figure out why your spec isn't running, make sure the file is named correctly.

Take a look for the top of the line that begins

RSpec.configure do |config|

A few lines down, you should see config.use_transactional_fixtures = true

Here is the important line that defines our use of transactional fixtures, as discussed in the introduction to this lesson. If you set this to false, you will switch Rspec into truncation strategy.

Towards the bottom of the RSpec.configure do |config| you will see another important config:

The infer_spec_type_from_file_location! setting. When enabled (which is just done by calling it with the bang method like you see here), specs will have added behaviors depending on what folder they are located in.

This is most relevant when we get to writing request specs and system specs, where we need either request spec helpers or Javascript, and so by putting the specs into these folders we are telling Rspec to run with either of these things.

Those are the most important parts of the rails_helper configuration, and in this tutorial, I will go over the default Rspec configuration only. Once you've finished the tutorial, feel free to explore the various settings.

Now that we have a Rspec installed, it is time to write your first spec. Exciting no?