Disposable tables for Rails tests
It turns out that it’s really easy to create tables and models dynamically within a Rails unit test. It’s a useful technique for reducing dependencies when testing.
To explain why you’d want to do this, imagine a hypothetical
acts_as_melon_farmer module that extends some models
in your Rails application with additional behaviour:
class Foo < ActiveRecord::Base acts_as_melon_farmer end class Bar < ActiveRecord::Base acts_as_melon_farmer end
What acting as a melon farmer really means is beyond the scope of this exercise.
The operation of the module depends on the ActiveRecord classes which it extends: in order to test the module, you need to provide that basic functionality.
One way to do this is to use an existing concrete class
(Foo or Bar in the example). This works,
but the tests are messy, poorly delineated, and brittle.
A better solution, perhaps, is to use mocking and stubbing to handle the interface between the module and ActiveRecord. However, one thing that’s very difficult to mock is the database—especially in ActiveRecord, where the SQL is exposed at a high level. If you want to test the actual behaviour of a particular query, you need to put it through the database layer. That means that you need a model definition and an associated database table.
As this model has no meaning outside the test, wouldn’t it be nice if you could create it in an entirely self-contained manner? Well, you can:
class ActsAsMelonFarmerTest < Test::Unit::TestCase
class Migration < ActiveRecord::Migration
def self.up
create_table 'melon_farmer_test_objects', :force => true do |t|
# column definitions
end
end
def self.down
drop_table 'melon_farmer_test_objects'
end
end
class MelonFarmerTestObject < ActiveRecord::Base
acts_as_melon_farmer
end
def setup
Migration.up
end
def teardown
Migration.down
end
# Your tests go here
end
I love it when there’s a clean solution to a problem.
I also need to pass on credit to Chris for suggesting that database migrations might work, and Ben, with whom I worked on this particular piece of code.