I was reading Greg Niewisiewicz’s blog post on 6 Gems to Make Rails Development Easier and saw the first recommendation was for a gem called temping. Nice. But here is my take on the same thing without adding a gem (sort of) and doing it with in-memory SQLite tables.
I’m using Rspec3, so these example will need modification if you are using MiniTest.
Gemfile
Ok, so you will need to add the sqlite3 gem to your Gemfile, if you don’t already have it in there. Because I am only using SQLite for testing, I put it in the :test group.
1 2 3 |
group :test do gem 'sqlite3' end |
Before(:all)
We need to create the table in SQLite via migration, then tell ActiveRecord to switch it’s database connection (temporarily) to use this in-memory db as the test environment database. We also add the ActiveRecord class so that we can, well, CRUD records.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
before(:all) do # don't output all the migration activity ActiveRecord::Migration.verbose = false # switch the active database connection to an SQLite, in-memory database ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") # execute the migration, creating a table (dirty_items) and columns (body, email, name) ActiveRecord::Schema.define(:version => 1) do create_table :dirty_items do |t| t.text :body t.text :email t.text :name end end # this creates the ActiveRecord class we will use, just like any other AR class class DirtyItem < ActiveRecord::Base # add anything you need for this class # this is the concern we are testing! include AttributeSanitizer end end |
After(:all)
We need to switch back to using your “test” database after all the tests are done in this spec. DON’T FORGET THIS STEP! Or all your other tests may fail, and you will be scratching your head why.
1 2 3 |
after(:all) do ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) end |
Good To Go
So now, you can operate on your temporary, in-memory, ActiveRecord table at lightning speed. And you don’t even need a gem. Just a few lines added to your test.
1 |
let(:dirty_item) { DirtyItem.new(body: 'humpty', email: 'dumpty', name: 'Ginger Ninja') } |
Caveat
Well, there is one downside, by using SQLite for the spec, you may not be using the database you would be running in production. This is true, unless you are using SQLite in production.
But, to be honest, you should try to be as database agnostic as possible. What if you have to switch from MySQL to PostgreSQL in the future for your production backend. Any MySQL database specific language you are using may fail in PostgreSQL.
On the plus side, the in-memory SQLite tables are really, really fast.
Thanks, this is a handy trick for testing gems that need to rely on AR too.
Thank you!!