Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added with additional settings for working with transactional fixture…

…s and pre-loaded test databases #865 [mindel]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@924 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit b2cfbc4cc9029252735a821a46c82ccc0f0b680d 1 parent 6717ed6
David Heinemeier Hansson dhh authored
2  activerecord/CHANGELOG
View
@@ -1,5 +1,7 @@
*SVN*
+* Added with additional settings for working with transactional fixtures and pre-loaded test databases #865 [mindel]
+
* Fixed acts_as_list to trigger remove_from_list on destroy after the fact, not before, so a unique position can be maintained #871 [Alisdair McDiarmid]
* Added the possibility of specifying fixtures in multiple calls #816 [kim@tinker.com]
76 activerecord/lib/active_record/fixtures.rb
View
@@ -121,6 +121,14 @@
# from a CSV fixture file would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
# fixtures available as instance variables @web_site_1 and @web_site_2.
#
+# If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
+#
+# - to completely disable instantiated fixtures:
+# self.use_instantiated_fixtures = false
+#
+# - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
+# self.use_instantiated_fixtures = :no_instances
+#
# = Dynamic fixtures with ERb
#
# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
@@ -164,6 +172,9 @@
# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
#
+# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
+# access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
+#
# When *not* to use transactional fixtures:
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
@@ -173,14 +184,25 @@
class Fixtures < Hash
DEFAULT_FILTER_RE = /\.ya?ml$/
- def self.instantiate_fixtures(object, table_name, fixtures)
+ def self.instantiate_fixtures(object, table_name, fixtures, load_instances=true)
object.instance_variable_set "@#{table_name}", fixtures
- fixtures.each do |name, fixture|
- if model = fixture.find
- object.instance_variable_set "@#{name}", model
+ if load_instances
+ fixtures.each do |name, fixture|
+ if model = fixture.find
+ object.instance_variable_set "@#{name}", model
+ end
end
end
end
+
+ def self.instantiate_all_loaded_fixtures(object, load_instances=true)
+ all_loaded_fixtures.each do |table_name, fixtures|
+ Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
+ end
+ end
+
+ cattr_accessor :all_loaded_fixtures
+ self.all_loaded_fixtures = {}
def self.create_fixtures(fixtures_directory, *table_names)
connection = block_given? ? yield : ActiveRecord::Base.connection
@@ -189,15 +211,17 @@ def self.create_fixtures(fixtures_directory, *table_names)
begin
ActiveRecord::Base.logger.level = Logger::ERROR
+ fixtures_map = {}
fixtures = table_names.flatten.map do |table_name|
- Fixtures.new(connection, File.split(table_name.to_s).last, File.join(fixtures_directory, table_name.to_s))
- end
-
+ fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, File.join(fixtures_directory, table_name.to_s))
+ end
+ all_loaded_fixtures.merge! fixtures_map
+
connection.transaction do
fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
fixtures.each { |fixture| fixture.insert_fixtures }
end
-
+
reset_sequences(connection, table_names) if connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
return fixtures.size > 1 ? fixtures : fixtures.first
@@ -360,19 +384,21 @@ class TestCase #:nodoc:
cattr_accessor :fixture_path
class_inheritable_accessor :fixture_table_names
class_inheritable_accessor :use_transactional_fixtures
- class_inheritable_accessor :use_instantiated_fixtures
+ class_inheritable_accessor :use_instantiated_fixtures # true, false, or :no_instances
+ class_inheritable_accessor :pre_loaded_fixtures
self.fixture_table_names = []
self.use_transactional_fixtures = false
self.use_instantiated_fixtures = true
+ self.pre_loaded_fixtures = false
def self.fixtures(*table_names)
self.fixture_table_names |= table_names.flatten
require_fixture_classes
end
- def self.require_fixture_classes
- fixture_table_names.each do |table_name|
+ def self.require_fixture_classes(table_names=nil)
+ (table_names || fixture_table_names).each do |table_name|
begin
require Inflector.singularize(table_name.to_s)
rescue LoadError
@@ -382,6 +408,10 @@ def self.require_fixture_classes
end
def setup_with_fixtures
+ if pre_loaded_fixtures && !use_transactional_fixtures
+ raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
+ end
+
# Load fixtures once and begin transaction.
if use_transactional_fixtures
load_fixtures unless @already_loaded_fixtures
@@ -438,13 +468,29 @@ def load_fixtures
@loaded_fixtures[table_name] = Fixtures.create_fixtures(fixture_path, table_name)
end
end
-
+
+ # for pre_loaded_fixtures, only require the classes once. huge speed improvement
+ @@required_fixture_classes = false
+
def instantiate_fixtures
- raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
- @loaded_fixtures.each do |table_name, fixtures|
- Fixtures.instantiate_fixtures(self, table_name, fixtures)
+ if pre_loaded_fixtures
+ raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
+ unless @@required_fixture_classes
+ self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
+ @@required_fixture_classes = true
+ end
+ Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
+ else
+ raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
+ @loaded_fixtures.each do |table_name, fixtures|
+ Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
+ end
end
end
+
+ def load_instances?
+ use_instantiated_fixtures != :no_instances
+ end
end
end
17 activerecord/test/fixtures_test.rb
View
@@ -113,8 +113,10 @@ class FixturesWithoutInstantiationTest < Test::Unit::TestCase
fixtures :topics, :developers, :accounts
def test_without_complete_instantiation
- assert_nil @topics
assert_nil @first
+ assert_nil @topics
+ assert_nil @developers
+ assert_nil @accounts
end
def test_fixtures_from_root_yml_without_instantiation
@@ -123,6 +125,19 @@ def test_fixtures_from_root_yml_without_instantiation
end
+class FixturesWithoutInstanceInstantiationTest < Test::Unit::TestCase
+ self.use_instantiated_fixtures = :no_instances
+ fixtures :topics, :developers, :accounts
+
+ def test_without_instance_instantiation
+ assert_nil @first
+ assert_not_nil @topics
+ assert_not_nil @developers
+ assert_not_nil @accounts
+ end
+end
+
+
class TransactionalFixturesTest < Test::Unit::TestCase
self.use_transactional_fixtures = true
fixtures :topics
Please sign in to comment.
Something went wrong with that request. Please try again.