5 minutes hack to speed up RSpec in Rails 5 using in-memory SQLite

2 minute read

Here is the story : you have a Rails 5 app that uses RSpec, but your RSpec suite is getting slower and slower to run. You’ve already considered some solutions :

  • Use SQLite in memory for your test env.
test:
  adapter: sqlite3
  database: ":memory:"

That’s the most straightforward thing to do, but unfortunately, if you are sharing your test env with Cucumber, you might want to use a production like DB with Cucumber (PostgreSQL or whatever). So unless you are ready to setup a new env for cucumber (which I tried and don’t recommend) you’re stuck.

  • Use mocks. That’s surely going to work, it’s going to make your test hell of a lot faster ! It will also make your tests a lot more fragile and more expensive to maintain … If you want to read more about why I think mocks are a bad idea, just have a look at these posts.

The hack

Here is a third alternative, I’ve already written about it, but here it comes updated and tested for Rails 5 :

  1. Don’t change anything to your config/database.yml
  2. Obviously, you’ll need to add sqlite3 to your Gemfile
  3. At the beginning of your spec/rails_helper.rb, replace
# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!

with

# In order to keep the same RAILS_ENV for rspec and cucumber, and to make rspec
# faster, patch the connection to use sqlite in memory when running rspec
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Schema.verbose = false
load "#{Rails.root.to_s}/db/schema.rb"

That’s it ! Run your specs … not bad for a 5 minutes investment !

Rails 5.1 (2017-03-29 Edit)

My fresh hack started to fail on Rails 5.1 ! If schema.rb is generated with the Postgres adapter, it is now incompatible with this injected Sqlite adapter. Here is a patch that removes the glitches :

# In order to keep the same RAILS_ENV for rspec and cucumber, and to make rspec
# faster, patch the connection to use sqlite in memory when running rspec
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Schema.verbose = false
# load db agnostic schema by default. Needed to remove the ", id: :serial" from
# the table definitions to make it load on sqlite
eval(`cat #{Rails.root.to_s}/db/schema.rb | sed 's/,[^:]*: :serial\//g'`)

I admit this is getting a bit crappy, and I don’t know how long it is going to work …

One more thing …

If you need even more speed, you can now run your specs in parallel in different processes ! Each in-memory SQLite DB is bound to its process, so unlike a real PostgreSQL dev DB, you won’t get any conflicts between your tests ;-)

I usually write about 15 minutes worth of reading per month. I won't transfer your email. No Spam, unsubscribe whenever you want.

As a gift for subscribing, you'll receive an illustrated mini-ebook "How to start a team coding dojo"!

Leave a comment