Rebuilding your test database from migrations
Today I submitted my first patch for the rails source.
Take a look here
The chief testing tasks in Rails are "test", "test:units", "test:functionals", ....
If you run
rake:test --traceyou'll get the following trace;
** Invoke test (first_time)
** Execute test
** Invoke test:units (first_time)
** Invoke db:test:prepare (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:test:prepare
** Invoke db:test:clone (first_time)
** Invoke db:schema:dump (first_time)
** Invoke environment
** Execute db:schema:dump
** Invoke db:test:purge (first_time)
** Invoke environment
** Execute db:test:purge
** Execute db:test:clone
** Invoke db:schema:load (first_time)
** Invoke environment
** Execute db:schema:load
** Execute test:units
It's a long trace, but the key is that it runs the following; db:test:prepare which does the following;
- purges the test database
- dumps the schema of the development* database
- rebuilds the test database with this dump
There are a few problems with this;
- If you run through rake, the test database will always be empty at boot, this can cause code which is fine in real circumstances to break just in these tests. Here's an obscure example;
class Model
Joins.find(:all).each do |join|
eval "has_many #{joins.name}, :foreign_key => #{joins.foreign_key}"
end
end
that's not the best example. But here's a better point.
If you have a "ModelTypes" table which has specific code attached. Whenever you add a new type, you'll add a migration to add this.
But you also need to update your fixtures.
Stick this in your environment.rb
Rails::Initializer.run do |config|
# Rebuild your database from your migrations in your tests
config.active_record.schema_format = :migrations
end
And stick a .rake file in lib/tasks with the following text
module Rake
class Task
attr_accessor :actions
end
end
# make sure its overwriting and not just adding to the method
Rake::Task["db:test:prepare"].prerequisites.clear
Rake::Task["db:test:prepare"].actions.clear
namespace :db do
namespace :test do
desc 'Drop and rebuild the test database from migrations'
task :rebuild_from_migrations => ["db:test:purge"] do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
ActiveRecord::Schema.verbose = false
Rake::Task["db:migrate"].invoke
end
desc 'Prepare the test database and load the schema'
task :prepare => :environment do
if defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
Rake::Task[{
:sql => "db:test:clone_structure",
:ruby => "db:test:clone",
:migrations => "db:test:rebuild_from_migrations"
}[ActiveRecord::Base.schema_format]].invoke
end
end
end
end
And you'll get exactly what I'm suggesting.The other thing perhaps worth doing is to run
"rake db:fixtures:load" in the same process.
(you'd have to turn off foreign keys, else it'd probably break.)