I have a configuration where, in addition to the local postgresql database, my Rails app also accesses a remote AWS database. My problem is that, even in tests that don't involve the remote database, the app establishes a connection to the remote database every time, so my tests run sloooooowly.
Is there a clean way to disable access to the remote database server for rspec tests that don't need it? (And enable it for those tests that do need it?)
The best I can think of is partition my rspec tests into two separate parts -- those that don't need to access the remote db and those that do -- and use environment variables to enable or disable parts of config/database.yaml accordingly.
To make this clear, my config/database.yaml
file contains (in part):
# file: config/database.yaml
# Define connections to the external database
remote:
adapter: mysql
database: remote
username: <%= ENV['PRODUCTION_DB_USERNAME'] || 'root' %>
password: <%= ENV['PRODUCTION_DB_PASSWORD'] || '' %>
host: awsserver-production-mysql.abcdef1234567890.us-west-2.rds.amazonaws.com
port: 3306
test:
adapter: postgresql
encoding: unicode
database: MyApp_test
pool: 5
username: <%= ENV['POSTGRESQL_DB_USERNAME'] || 'MyApp' %>
password: <%= ENV['POSTGRESQL_DB_PASSWORD'] || '' %>
(NOTE: In case you're wondering, using mocks won't help: the remote db connection is established even before the tests start to run. And vcr only intercepts HTTP connections -- database connections use a different mechanism.)
I've found examples of how to dynamically establish a connection:
def connect_to_myapp_database
ActiveRecord::Base.establish_connection(:adapter => "mysql",
:database => 'myapp',
:username => ENV['MYAPP_DB_USERNAME'],
:password => ENV['MYAPP_DB_PASSWORD'],
:host => 'mayapp-mysql.abcdefg123456.us-west-2.rds.amazonaws.com',
:port => 3306,
)
end
which works fine -- I can use this to connect to the external database just for those tests that need it. But this begs the question: how do I disconnect from the external database once I've done this?
Use nulldb when you're testing and the real db otherwise. Here's how:
First, include this in your Gemfile:
group :development, :test do
gem 'activerecord-nulldb-adapter', :git => 'git://github.com/nulldb/nulldb.git'
end
and then do the usual bundle install
Define a base class for all models that are backed in the external database:
class ExternalModel < ActiveRecord::Base
if Rails.app.test?
establish_connection(:adapter => :nulldb)
else
establish_connection(:myapp)
end
def readonly?; true; end
end
Then all the external models inherit from ExternalModel (I should have done this from the start):
class ExternalUser < ExternalModel
...
end
When run in a test environment, it won't try to connect to the external table. Of course, attempts to access an instance of ExternalUser will fail, but you can selectively establish a connection with the external database during integration testing, or stub or mock references to the external model otherwise.
Most importantly, all my tests run really fast now.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.