4 require 'active_support/dependencies'
5 require 'active_support/test_case'
7 if RUBY_VERSION < '1.9'
10 def keys
; map
{ |k
, v
| k
} end
11 def values
; map
{ |k
, v
| v
} end
16 if defined? ActiveRecord
17 class FixtureClassNotFound
< ActiveRecord
::ActiveRecordError #:nodoc:
20 class FixtureClassNotFound
< StandardError
#:nodoc:
24 # Fixtures are a way of organizing data that you want to test against; in short, sample data.
28 # Fixtures come in 3 flavors:
32 # 3. Single-file fixtures
36 # This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
37 # in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.
39 # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed
40 # by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
41 # put your files in <tt><your-rails-app>/test/fixtures/</tt>). The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
42 # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a YAML fixture file looks like this:
47 # url: http://www.rubyonrails.org
52 # url: http://www.google.com
54 # This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an
55 # indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing
58 # Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. See http://yaml.org/type/omap.html
59 # for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table.
60 # This is commonly needed for tree structures. Example:
74 # Fixtures can also be kept in the Comma Separated Value (CSV) format. Akin to YAML fixtures, CSV fixtures are stored
75 # in a single file, but instead end with the <tt>.csv</tt> file extension
76 # (Rails example: <tt><your-rails-app>/test/fixtures/web_sites.csv</tt>).
78 # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
79 # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised
80 # of the actual data (1 per line). Here's an example:
83 # 1, Ruby On Rails, http://www.rubyonrails.org
84 # 2, Google, http://www.google.com
86 # Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you
87 # need to use a double quote character, you must escape it with another double quote.
89 # Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats. Instead, the
90 # fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
91 # number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
94 # Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
95 # have existing data somewhere already.
97 # == Single-file fixtures
99 # This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
100 # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
101 # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
102 # put your files in <tt><your-rails-app>/test/fixtures/<your-model-name>/</tt> --
103 # like <tt><your-rails-app>/test/fixtures/web_sites/</tt> for the WebSite model).
105 # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
106 # extensions, but if you are on a Windows machine, you might consider adding <tt>.txt</tt> as the extension. Here's what the
107 # above example might look like:
110 # web_sites/yahoo.txt
111 # web_sites/ruby-on-rails
113 # The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax
114 # of "name => value". Here's an example of the ruby-on-rails fixture above:
117 # name => Ruby on Rails
118 # url => http://www.rubyonrails.org
120 # = Using fixtures in testcases
122 # Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
123 # fixtures, but first let's take a look at a sample unit test:
125 # require 'test_helper'
127 # class WebSiteTest < ActiveSupport::TestCase
128 # test "web_site_count" do
129 # assert_equal 2, WebSite.count
133 # By default, the <tt>test_helper module</tt> will load all of your fixtures into your test database, so this test will succeed.
134 # The testing environment will automatically load the all fixtures into the database before each test.
135 # To ensure consistent data, the environment deletes the fixtures before running the load.
137 # In addition to being available in the database, the fixture's data may also be accessed by
138 # using a special dynamic method, which has the same name as the model, and accepts the
139 # name of the fixture to instantiate:
142 # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
145 # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the following tests:
147 # test "find_alt_method_1" do
148 # assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
151 # test "find_alt_method_2" do
152 # assert_equal "Ruby on Rails", @rubyonrails.news
155 # In order to use these methods to access fixtured data within your testcases, you must specify one of the
156 # following in your <tt>ActiveSupport::TestCase</tt>-derived class:
158 # - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
159 # self.use_instantiated_fixtures = true
161 # - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
162 # self.use_instantiated_fixtures = :no_instances
164 # Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
165 # traversed in the database to create the fixture hash and/or instance variables. This is expensive for
166 # large sets of fixtured data.
168 # = Dynamic fixtures with ERb
170 # 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
171 # mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
173 # <% for i in 1..1000 %>
179 # This will create 1000 very simple YAML fixtures.
181 # Using ERb, you can also inject dynamic values into your fixtures with inserts like <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
182 # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable
183 # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application
184 # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.
186 # = Transactional fixtures
188 # TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case.
190 # class FooTest < ActiveSupport::TestCase
191 # self.use_transactional_fixtures = true
194 # assert !Foo.find(:all).empty?
196 # assert Foo.find(:all).empty?
199 # test "godzilla aftermath" do
200 # assert !Foo.find(:all).empty?
204 # If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
205 # 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.
207 # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
208 # access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
210 # When *not* to use transactional fixtures:
212 # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
213 # particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
214 # the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
215 # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
216 # Use InnoDB, MaxDB, or NDB instead.
218 # = Advanced YAML Fixtures
220 # YAML fixtures that don't specify an ID get some extra features:
222 # * Stable, autogenerated IDs
223 # * Label references for associations (belongs_to, has_one, has_many)
224 # * HABTM associations as inline lists
225 # * Autofilled timestamp columns
226 # * Fixture label interpolation
227 # * Support for YAML defaults
229 # == Stable, autogenerated IDs
231 # Here, have a monkey fixture:
235 # name: George the Monkey
239 # name: Reginald the Pirate
241 # Each of these fixtures has two unique identifiers: one for the database
242 # and one for the humans. Why don't we generate the primary key instead?
243 # Hashing each fixture's label yields a consistent ID:
245 # george: # generated id: 503576764
246 # name: George the Monkey
248 # reginald: # generated id: 324201669
249 # name: Reginald the Pirate
251 # Active Record looks at the fixture's model class, discovers the correct
252 # primary key, and generates it right before inserting the fixture
255 # The generated ID for a given label is constant, so we can discover
256 # any fixture's ID without loading anything, as long as we know the label.
258 # == Label references for associations (belongs_to, has_one, has_many)
260 # Specifying foreign keys in fixtures can be very fragile, not to
261 # mention difficult to read. Since Active Record can figure out the ID of
262 # any fixture from its label, you can specify FK's by label instead of ID.
266 # Let's break out some more monkeys and pirates.
272 # name: Reginald the Pirate
279 # name: George the Monkey
282 # Add a few more monkeys and pirates and break this into multiple files,
283 # and it gets pretty hard to keep track of what's going on. Let's
284 # use labels instead of IDs:
289 # name: Reginald the Pirate
295 # name: George the Monkey
298 # Pow! All is made clear. Active Record reflects on the fixture's model class,
299 # finds all the +belongs_to+ associations, and allows you to specify
300 # a target *label* for the *association* (monkey: george) rather than
301 # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
303 # ==== Polymorphic belongs_to
305 # Supporting polymorphic relationships is a little bit more complicated, since
306 # Active Record needs to know what type your association is pointing at. Something
307 # like this should look familiar:
311 # belongs_to :eater, :polymorphic => true
321 # Can we do better? You bet!
324 # eater: george (Monkey)
326 # Just provide the polymorphic target type and Active Record will take care of the rest.
328 # === has_and_belongs_to_many
330 # Time to give our monkey some fruit.
336 # name: George the Monkey
353 # ### in fruits_monkeys.yml
367 # Let's make the HABTM fixture go away.
372 # name: George the Monkey
374 # fruits: apple, orange, grape
387 # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
388 # on George's fixture, but we could've just as easily specified a list
389 # of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
390 # the fixture's model class and discovers the +has_and_belongs_to_many+
393 # == Autofilled timestamp columns
395 # If your table/model specifies any of Active Record's
396 # standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
397 # they will automatically be set to <tt>Time.now</tt>.
399 # If you've set specific values, they'll be left alone.
401 # == Fixture label interpolation
403 # The label of the current fixture is always available as a column value:
406 # name: Geeksomnia's Account
409 # Also, sometimes (like when porting older join table fixtures) you'll need
410 # to be able to get ahold of the identifier for a given label. ERB
414 # monkey_id: <%= Fixtures.identify(:reginald) %>
415 # pirate_id: <%= Fixtures.identify(:george) %>
417 # == Support for YAML defaults
419 # You probably already know how to use YAML to set and reuse defaults in
420 # your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
422 # DEFAULTS: &DEFAULTS
423 # created_on: <%= 3.weeks.ago.to_s(:db) %>
433 # Any fixture labeled "DEFAULTS" is safely ignored.
435 class Fixtures
< (RUBY_VERSION < '1.9' ? YAML
::Omap : Hash
)
436 DEFAULT_FILTER_RE
= /\.ya?ml$/
438 @
@all_cached_fixtures = {}
440 def self.reset_cache(connection
= nil)
441 connection
||= ActiveRecord
::Base.connection
442 @
@all_cached_fixtures[connection
.object_id
] = {}
445 def self.cache_for_connection(connection
)
446 @
@all_cached_fixtures[connection
.object_id
] ||= {}
447 @
@all_cached_fixtures[connection
.object_id
]
450 def self.fixture_is_cached
?(connection
, table_name
)
451 cache_for_connection(connection
)[table_name
]
454 def self.cached_fixtures(connection
, keys_to_fetch
= nil)
456 fixtures
= cache_for_connection(connection
).values_at(*keys_to_fetch
)
458 fixtures
= cache_for_connection(connection
).values
460 fixtures
.size
> 1 ? fixtures
: fixtures
.first
463 def self.cache_fixtures(connection
, fixtures_map
)
464 cache_for_connection(connection
).update(fixtures_map
)
467 def self.instantiate_fixtures(object
, table_name
, fixtures
, load_instances
= true)
468 object
.instance_variable_set
"@#{table_name.to_s.gsub('.','_')}", fixtures
470 ActiveRecord
::Base.silence
do
471 fixtures
.each
do |name
, fixture
|
473 object
.instance_variable_set
"@#{name}", fixture
.find
474 rescue FixtureClassNotFound
482 def self.instantiate_all_loaded_fixtures(object
, load_instances
= true)
483 all_loaded_fixtures
.each
do |table_name
, fixtures
|
484 Fixtures
.instantiate_fixtures(object
, table_name
, fixtures
, load_instances
)
488 cattr_accessor
:all_loaded_fixtures
489 self.all_loaded_fixtures
= {}
491 def self.create_fixtures(fixtures_directory
, table_names
, class_names
= {})
492 table_names
= [table_names
].flatten
.map
{ |n
| n
.to_s
}
493 connection
= block_given
? ? yield : ActiveRecord
::Base.connection
495 table_names_to_fetch
= table_names
.reject
{ |table_name
| fixture_is_cached
?(connection
, table_name
) }
497 unless table_names_to_fetch
.empty
?
498 ActiveRecord
::Base.silence
do
499 connection
.disable_referential_integrity
do
502 fixtures
= table_names_to_fetch
.map
do |table_name
|
503 fixtures_map
[table_name
] = Fixtures
.new(connection
, File
.split(table_name
.to_s
).last
, class_names
[table_name
.to_sym
], File
.join(fixtures_directory
, table_name
.to_s
))
506 all_loaded_fixtures
.update(fixtures_map
)
508 connection
.transaction(:requires_new => true) do
509 fixtures
.reverse
.each
{ |fixture
| fixture
.delete_existing_fixtures
}
510 fixtures
.each
{ |fixture
| fixture
.insert_fixtures
}
512 # Cap primary key sequences to max(pk).
513 if connection
.respond_to
?(:reset_pk_sequence!)
514 table_names
.each
do |table_name
|
515 connection
.reset_pk_sequence
!(table_name
)
520 cache_fixtures(connection
, fixtures_map
)
524 cached_fixtures(connection
, table_names
)
527 # Returns a consistent identifier for +label+. This will always
528 # be a positive integer, and will always be the same for a given
529 # label, assuming the same OS, platform, and version of Ruby.
530 def self.identify(label
)
534 attr_reader
:table_name, :name
536 def initialize(connection
, table_name
, class_name
, fixture_path
, file_filter
= DEFAULT_FILTER_RE
)
537 @connection, @table_name, @fixture_path, @file_filter = connection
, table_name
, fixture_path
, file_filter
538 @name = table_name
# preserve fixture base name
539 @class_name = class_name
||
540 (ActiveRecord
::Base.pluralize_table_names
? @table_name.singularize
.camelize
: @table_name.camelize
)
541 @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}"
542 @table_name = class_name
.table_name
if class_name
.respond_to
?(:table_name)
543 @connection = class_name
.connection
if class_name
.respond_to
?(:connection)
547 def delete_existing_fixtures
548 @connection.delete
"DELETE FROM #{@connection.quote_table_name(table_name)}", 'Fixture Delete'
552 now
= ActiveRecord
::Base.default_timezone
== :utc ? Time
.now
.utc
: Time
.now
555 # allow a standard key to be used for doing defaults in YAML
559 delete(assoc('DEFAULTS'))
562 # track any join tables we need to insert later
563 habtm_fixtures
= Hash
.new
do |h
, habtm
|
564 h
[habtm
] = HabtmFixtures
.new(@connection, habtm
.options
[:join_table], nil, nil)
567 each
do |label
, fixture
|
568 row
= fixture
.to_hash
570 if model_class
&& model_class
< ActiveRecord
::Base
571 # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
572 if model_class
.record_timestamps
573 timestamp_column_names
.each
do |name
|
574 row
[name
] = now
unless row
.key
?(name
)
578 # interpolate the fixture label
579 row
.each
do |key
, value
|
580 row
[key
] = label
if value
== "$LABEL"
583 # generate a primary key if necessary
584 if has_primary_key_column
? && !row
.include?(primary_key_name
)
585 row
[primary_key_name
] = Fixtures
.identify(label
)
588 # If STI is used, find the correct subclass for association reflection
590 if row
.include?(inheritance_column_name
)
591 row
[inheritance_column_name
].constantize
rescue model_class
596 reflection_class
.reflect_on_all_associations
.each
do |association
|
597 case association
.macro
599 # Do not replace association name with association foreign key if they are named the same
600 fk_name
= (association
.options
[:foreign_key] || "#{association.name}_id").to_s
602 if association
.name
.to_s
!= fk_name
&& value
= row
.delete(association
.name
.to_s
)
603 if association
.options
[:polymorphic]
604 if value
.sub
!(/\s*\(([^\)]*)\)\s*$/, "")
606 target_type_name
= (association
.options
[:foreign_type] || "#{association.name}_type").to_s
608 # support polymorphic belongs_to as "label (Type)"
609 row
[target_type_name
] = target_type
613 row
[fk_name
] = Fixtures
.identify(value
)
615 when :has_and_belongs_to_many
616 if (targets
= row
.delete(association
.name
.to_s
))
617 targets
= targets
.is_a
?(Array
) ? targets
: targets
.split(/\s*,\s*/)
618 join_fixtures
= habtm_fixtures
[association
]
620 targets
.each
do |target
|
621 join_fixtures
["#{label}_#{target}"] = Fixture
.new(
622 { association
.primary_key_name
=> row
[primary_key_name
],
623 association
.association_foreign_key
=> Fixtures
.identify(target
) }, nil)
630 @connection.insert_fixture(fixture
, @table_name)
633 # insert any HABTM join tables we discovered
634 habtm_fixtures
.values
.each
do |fixture
|
635 fixture
.delete_existing_fixtures
636 fixture
.insert_fixtures
641 class HabtmFixtures
< ::Fixtures #:nodoc:
642 def read_fixture_files
; end
646 unless defined?(@model_class)
648 if @class_name.nil? || @class_name.is_a
?(Class
)
651 @class_name.constantize
rescue nil
659 @primary_key_name ||= model_class
&& model_class
.primary_key
662 def has_primary_key_column
?
663 @has_primary_key_column ||= model_class
&& primary_key_name
&&
664 model_class
.columns
.find
{ |c
| c
.name
== primary_key_name
}
667 def timestamp_column_names
668 @timestamp_column_names ||= %w(created_at created_on updated_at updated_on
).select
do |name
|
669 column_names
.include?(name
)
673 def inheritance_column_name
674 @inheritance_column_name ||= model_class
&& model_class
.inheritance_column
678 @column_names ||= @connection.columns(@table_name).collect(&:name)
681 def read_fixture_files
682 if File
.file
?(yaml_file_path
)
683 read_yaml_fixture_files
684 elsif File
.file
?(csv_file_path
)
685 read_csv_fixture_files
689 def read_yaml_fixture_files
691 Dir
["#{@fixture_path}/**/*.yml"].select
{ |f
| test(?f
, f
) }.each
do |subfixture_path
|
692 yaml_string
<< IO
.read(subfixture_path
)
694 yaml_string
<< IO
.read(yaml_file_path
)
696 if yaml
= parse_yaml_string(yaml_string
)
697 # If the file is an ordered map, extract its children.
699 if yaml
.respond_to
?(:type_id) && yaml
.respond_to
?(:value)
705 yaml_value
.each
do |fixture
|
706 raise Fixture
::FormatError, "Bad data for #{@class_name} fixture named #{fixture}" unless fixture
.respond_to
?(:each)
707 fixture
.each
do |name
, data|
709 raise Fixture
::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
712 self[name
] = Fixture
.new(data, model_class
)
718 def read_csv_fixture_files
719 reader
= CSV
.parse(erb_render(IO
.read(csv_file_path
)))
720 header
= reader
.shift
724 row
.each_with_index
{ |cell
, j
| data[header
[j
].to_s
.strip
] = cell
.to_s
.strip
}
725 self["#{@class_name.to_s.underscore}_#{i+=1}"] = Fixture
.new(data, model_class
)
730 "#{@fixture_path}.yml"
734 @fixture_path + ".csv"
737 def yaml_fixtures_key(path
)
738 File
.basename(@fixture_path).split(".").first
741 def parse_yaml_string(fixture_content
)
742 YAML
::load(erb_render(fixture_content
))
744 raise Fixture
::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}"
747 def erb_render(fixture_content
)
748 ERB
.new(fixture_content
).result
752 class Fixture
#:nodoc:
755 class FixtureError
< StandardError
#:nodoc:
758 class FormatError
< FixtureError
#:nodoc:
761 attr_reader
:model_class
763 def initialize(fixture
, model_class
)
765 @model_class = model_class
.is_a
?(Class
) ? model_class
: model_class
.constantize
rescue nil
769 @model_class.name
if @model_class
773 @fixture.each
{ |item
| yield item
}
785 columns
= @fixture.keys
.collect
{ |column_name
| ActiveRecord
::Base.connection
.quote_column_name(column_name
) }
790 list
= @fixture.inject([]) do |fixtures
, (key
, value
)|
791 col
= model_class
.columns_hash
[key
] if model_class
.respond_to
?(:ancestors) && model_class
.ancestors
.include?(ActiveRecord
::Base)
792 fixtures
<< ActiveRecord
::Base.connection
.quote(value
, col
).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r")
799 model_class
.find(self[model_class
.primary_key
])
801 raise FixtureClassNotFound
, "No class attached to find."
808 def self.included(base
)
810 setup
:setup_fixtures
811 teardown
:teardown_fixtures
813 superclass_delegating_accessor
:fixture_path
814 superclass_delegating_accessor
:fixture_table_names
815 superclass_delegating_accessor
:fixture_class_names
816 superclass_delegating_accessor
:use_transactional_fixtures
817 superclass_delegating_accessor
:use_instantiated_fixtures # true, false, or :no_instances
818 superclass_delegating_accessor
:pre_loaded_fixtures
820 self.fixture_table_names
= []
821 self.use_transactional_fixtures
= false
822 self.use_instantiated_fixtures
= true
823 self.pre_loaded_fixtures
= false
825 self.fixture_class_names
= {}
828 base
.extend ClassMethods
832 def set_fixture_class(class_names
= {})
833 self.fixture_class_names
= self.fixture_class_names
.merge(class_names
)
836 def fixtures(*table_names
)
837 if table_names
.first
== :all
838 table_names
= Dir
["#{fixture_path}/*.yml"] + Dir
["#{fixture_path}/*.csv"]
839 table_names
.map
! { |f
| File
.basename(f
).split('.')[0..-2].join('.') }
841 table_names
= table_names
.flatten
.map
{ |n
| n
.to_s
}
844 self.fixture_table_names
|= table_names
845 require_fixture_classes(table_names
)
846 setup_fixture_accessors(table_names
)
849 def try_to_load_dependency(file_name
)
850 require_dependency file_name
851 rescue LoadError
=> e
852 # Let's hope the developer has included it himself
854 # Let's warn in case this is a subdependency, otherwise
855 # subdependency error messages are totally cryptic
856 if ActiveRecord
::Base.logger
857 ActiveRecord
::Base.logger
.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
861 def require_fixture_classes(table_names
= nil)
862 (table_names
|| fixture_table_names
).each
do |table_name
|
863 file_name
= table_name
.to_s
864 file_name
= file_name
.singularize
if ActiveRecord
::Base.pluralize_table_names
865 try_to_load_dependency(file_name
)
869 def setup_fixture_accessors(table_names
= nil)
870 table_names
= [table_names
] if table_names
&& !table_names
.respond_to
?(:each)
871 (table_names
|| fixture_table_names
).each
do |table_name
|
872 table_name
= table_name
.to_s
.tr('.', '_')
874 define_method(table_name
) do |*fixtures
|
875 force_reload
= fixtures
.pop
if fixtures
.last
== true || fixtures
.last
== :reload
877 @fixture_cache[table_name
] ||= {}
879 instances
= fixtures
.map
do |fixture
|
880 @fixture_cache[table_name
].delete(fixture
) if force_reload
882 if @loaded_fixtures[table_name
][fixture
.to_s
]
883 @fixture_cache[table_name
][fixture
] ||= @loaded_fixtures[table_name
][fixture
.to_s
].find
885 raise StandardError
, "No fixture with name '#{fixture}' found for table '#{table_name}'"
889 instances
.size
== 1 ? instances
.first
: instances
894 def uses_transaction(*methods
)
895 @uses_transaction = [] unless defined?(@uses_transaction)
896 @uses_transaction.concat methods
.map(&:to_s)
899 def uses_transaction
?(method
)
900 @uses_transaction = [] unless defined?(@uses_transaction)
901 @uses_transaction.include?(method
.to_s
)
905 def run_in_transaction
?
906 use_transactional_fixtures
&&
907 !self.class.uses_transaction
?(method_name
)
911 return unless defined?(ActiveRecord
) && !ActiveRecord
::Base.configurations
.blank
?
913 if pre_loaded_fixtures
&& !use_transactional_fixtures
914 raise RuntimeError
, 'pre_loaded_fixtures requires use_transactional_fixtures'
918 @
@already_loaded_fixtures ||= {}
920 # Load fixtures once and begin transaction.
921 if run_in_transaction
?
922 if @
@already_loaded_fixtures[self.class]
923 @loaded_fixtures = @
@already_loaded_fixtures[self.class]
926 @
@already_loaded_fixtures[self.class] = @loaded_fixtures
928 ActiveRecord
::Base.connection
.increment_open_transactions
929 ActiveRecord
::Base.connection
.transaction_joinable
= false
930 ActiveRecord
::Base.connection
.begin_db_transaction
931 # Load fixtures for every test.
934 @
@already_loaded_fixtures[self.class] = nil
938 # Instantiate fixtures for every test if requested.
939 instantiate_fixtures
if use_instantiated_fixtures
942 def teardown_fixtures
943 return unless defined?(ActiveRecord
) && !ActiveRecord
::Base.configurations
.blank
?
945 unless run_in_transaction
?
949 # Rollback changes if a transaction is active.
950 if run_in_transaction
? && ActiveRecord
::Base.connection
.open_transactions
!= 0
951 ActiveRecord
::Base.connection
.rollback_db_transaction
952 ActiveRecord
::Base.connection
.decrement_open_transactions
954 ActiveRecord
::Base.clear_active_connections
!
959 @loaded_fixtures = {}
960 fixtures
= Fixtures
.create_fixtures(fixture_path
, fixture_table_names
, fixture_class_names
)
962 if fixtures
.instance_of
?(Fixtures
)
963 @loaded_fixtures[fixtures
.name
] = fixtures
965 fixtures
.each
{ |f
| @loaded_fixtures[f
.name
] = f
}
970 # for pre_loaded_fixtures, only require the classes once. huge speed improvement
971 @
@required_fixture_classes = false
973 def instantiate_fixtures
974 if pre_loaded_fixtures
975 raise RuntimeError
, 'Load fixtures before instantiating them.' if Fixtures
.all_loaded_fixtures
.empty
?
976 unless @
@required_fixture_classes
977 self.class.require_fixture_classes Fixtures
.all_loaded_fixtures
.keys
978 @
@required_fixture_classes = true
980 Fixtures
.instantiate_all_loaded_fixtures(self, load_instances
?)
982 raise RuntimeError
, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
983 @loaded_fixtures.each
do |table_name
, fixtures
|
984 Fixtures
.instantiate_fixtures(self, table_name
, fixtures
, load_instances
?)
990 use_instantiated_fixtures
!= :no_instances