RoR: how do I test my app against multiple databases?
I started deploying my latest RoR app on Heroku
, which required me to start using PostgreSQL -- I'd previously been using SQLite and MySQL. I wanted a dead-simple way to continually do red/green testing against all three databases to make sure I didn't break anything in the heat of development.
What's a good way to do this?开发者_开发技巧
@awendt kindly pointed out that I could answer my own question.
It turns out the recipe is rather simple. The secret is to use a environment variable to tell Rails which db you want to use.
1. Modifying your files
In config/database.yml
, include ERB constructs like this:
test:
<% if (ENV["RAILS_DB"] == "PostgreSQL") %>
adapter: postgresql
encoding: unicode
database: bd_test
pool: 5
username: <%= ENV['POSTGRESQL_USERNAME'] || 'root' %>
password: <%= ENV['POSTGRESQL_PASSWORD'] || '' %>
<% elsif (ENV["RAILS_DB"] == "MySQL") %>
adapter: mysql
encoding: utf8
reconnect: false
database: bd_test
pool: 5
username: <%= ENV['MYSQL_USERNAME'] || 'root' %>
password: <%= ENV['MYSQL_PASSWORD'] || '' %>
socket: <%= ENV['MYSQL_SOCKET'] || '/tmp/mysql.sock' %>
<% else %>
# default to SQLite
adapter: sqlite3
database: db/test.sqlite3
pool: 5
timeout: 5000
<% end %>
Note 1: I've only shown it for the test environment. In fact, that's the only one I've modified, since (supposedly) it provides enough coverage to tell me if all three databases are properly supported.
Note 2: You don't need to use environment variables to set username and password -- that's just something I prefer to do since it avoids exposing passwords in a commonly viewed file.
Similarly, extend Gemfile as follows (note that your version numbers may vary):
source 'http://rubygems.org'
gem 'rails', '3.0.3'
case ENV["RAILS_DB"]
when "PostgreSQL"
gem 'pg', '0.10.0'
when "MySQL"
gem 'mysql2'
else
gem 'sqlite3', '1.3.3'
gem 'sqlite3-ruby', '1.3.3', :require => 'sqlite3'
end
...
2. Add conditions to your code
Despite the best efforts of the Rails development team, there are a few spots where ActiveRecord constructs aren't compatible across all flavors of database. In these cases, you can condition your code on ActiveRecord::Base.connection.adapter_name
. Here's an example from one of my migration files:
file: migrate/20110129023453_create_cached_web_pages.rb
def self.up
create_table :cached_web_pages do |t|
t.string :key
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
t.binary :value
else
t.binary :value, :limit => 16777215
end
end
end
...
3. Running and testing
You can now select a database simply by setting the RAILS_DB environment variable, but there's a catch: you have to run bundle install
each time to set up the appropriate database adaptor from the Gemfile. Fortunately, that's exactly what the test code does. So, for example, I can run rspec's autotest in two windows:
$ RAILS_DB=SQLite autotest
and
$ RAILS_DB=PostgreSQL autotest
Now I can hack away at my files and autotest will quietly alert me if I've broken anything as I go along.
精彩评论