[Peter Marklund][1] has an example gist of testing a migration here:
[To see links please register here]
(in rspec).
Note migrations have changed since his example to use instance methods instead of class methods.
Here's a summary:
1. Create a migration as usual
2. Create a file to put your migration test in. Suggestions: `test/unit/import_legacy_devices_migration_test.rb` or `spec/migrations/import_legacy_devices_migration_spec.rb`
NOTE: you probably need to explicitly load the migration file as rails will probably not load it for you. Something like this should do: `require File.join(Rails.root, 'db', 'migrate', '20101110154036_import_legacy_devices')`
3. Migrations are (like everything in ruby), just a class. Test the `up` and `down` methods. If your logic is complex, I suggest refactoring out bits of logic to smaller methods that will be easier to test.
4. Before calling `up`, set up some some data as it would be before your migration, and assert that it's state is what you expect afterward.
I hope this helps.
**UPDATE**: Since posting this, I posted on my blog an [example migration test][2].
**UPDATE**: Here's an idea for testing migrations even after they've been run in development.
**EDIT**: I've updated my proof-of-concept to a full spec file using the contrived example from my blog post.
<!-- Language: Ruby -->
# spec/migrations/add_email_at_utc_hour_to_users_spec.rb
require 'spec_helper'
migration_file_name = Dir[Rails.root.join('db/migrate/*_add_email_at_utc_hour_to_users.rb')].first
require migration_file_name
describe AddEmailAtUtcHourToUsers do
# This is clearly not very safe or pretty code, and there may be a
# rails api that handles this. I am just going for a proof of concept here.
def migration_has_been_run?(version)
table_name = ActiveRecord::Migrator.schema_migrations_table_name
query = "SELECT version FROM %s WHERE version = '%s'" % [table_name, version]
ActiveRecord::Base.connection.execute(query).any?
end
let(:migration) { AddEmailAtUtcHourToUsers.new }
before do
# You could hard-code the migration number, or find it from the filename...
if migration_has_been_run?('20120425063641')
# If this migration has already been in our current database, run down first
migration.down
end
end
describe '#up' do
before { migration.up; User.reset_column_information }
it 'adds the email_at_utc_hour column' do
User.columns_hash.should have_key('email_at_utc_hour')
end
end
end
[1]:
[To see links please register here]
[2]:
[To see links please register here]