Using instantiated fixtures with multiple database access
V návaznosti na implementaci projektu používající vícenásobný databázaový přístup, jsem byl nucem vytvořit adekvátní testovací prostředí. Následující text je také uveden na http://wiki.rubyonrails.com/rails/pages/HowtoUseMultipleDatabasesWithFixtures
Using instantiated fixtures with multiple databases without modifying AR
RoR testing with instantiated fixtures while using multiple databases is more possible then ever. All you need to do is just implement your own test_helper method, that load fixtures into the databases and instatiate them. Here’s my code, which i use in my project(just copy it into test_helper.rb):
cattr_accessor :classes_cache
#class cache for storing already founded classes from models
@@classes_cache = {}
def load_user_fixtures(*table_names)
fixtures = {}
table_names = table_names.flatten.collect{|t| t.to_s}
table_names.each do |table_name|
unless @@classes_cache[table_name].nil?
klas = @@classes_cache[table_name]
else
begin
#try to find class name from table name
klas = eval(table_name.classify)
rescue
#go to model directory, run through all models and search for table name
classes = Dir.entries(RAILS_ROOT + "/app/models").select{|d| d.include?(".rb")}.collect{|f| File.basename(f, ".rb").classify}
klas_names = classes.select{|f| (eval("#{f}.table_name") rescue false)==table_name }
klas_name = klas_names.blank? ? table_name.classify : klas_names.first
klas = eval(klas_name)
end
@@classes_cache[table_name] = klas
end
#load fixture
fixtures[table_name] = Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_name,
{table_name.to_sym => klas.name}){klas.connection}
end
#run through all fixtures and instantiate them
fixtures.each_pair do |table_name, fixs|
Fixtures.instantiate_fixtures(self, table_name, fixs)
end
end
Disable transactional and instantiated fixtures
self.use_transactional_fixtures = false
self.use_instantiated_fixtures = false
To load your fixtures in tests use implemented helper method in your unit or functional tests like this(notice, that load_user_fixtures is instance method, but regular fixtures method is class method)
require File.dirname(__FILE__) + '/../test_helper'
class EmployeeTest < Test::Unit::TestCase
def setup
load_user_fixtures :employees, :users
end
end
AR has a small bug when asking for table_name to class, which is inherited from abstract class. So we have to set table names even if they are the same as model name.
First set abstract class as usual to define connection.
class AnotherDatabaseConnector < ActiveRecord::Base
self.abstract_class = true
establish_connection "another_database_#{RAILS_ENV}"
# all subclasses use connection from here
end
All your subclasses accessing another database will look like this. We have to set table name for those, inherited from our abstract class.
class User < AnotherDatabaseConnector
set_table_name "users" # we need to set this explicitly
end
I done this, because i had many tests already done, and i was too lazy to rewrite them for non-instantiated fixtures, and it works, you don’t have to change anything in AR, you don’t have to set DB connections in tests, all you have to do is just use this method to load fixtures instead of default method fixtures.
If you have any problems or suggestions, you can discuss email me robert.cigan@skvely.cz, or chat directly using ICQ 82645774
- rimmer
Posted in Programování | no comments | atom