まず結論から
setup
でfixtureを使う時は、teardown
でfixtureのキャッシュを消しましょう。
fixtureが読み込まれない現象
まずは問題のあるコードを掲載します。SecondTest
のsome test 2
テストを見てください。TableClass
のテーブルにfixtureデータが入っていません。
require 'test_helper'
class FirstTest < ActiveSupport::TestCase
setup do
fixture_directory = ''
fixture_files = [:tbl]
fixture_models = { tbl: TableClass }
ActiveRecord::FixtureSet.create_fixtures(fixture_directory, fixture_files, fixture_models, DBClass)
end
test 'some test 1' do
pp TableClass.all #=> [...]
end
end
class SecondTest < ActiveSupport::TestCase
setup do
fixture_directory = ''
fixture_files = [:tbl]
fixture_models = { tbl: TableClass }
ActiveRecord::FixtureSet.create_fixtures(fixture_directory, fixture_files, fixture_models, DBClass)
end
test 'some test 2' do
pp TableClass.all #=> []
end
end
この挙動を理解するためには、次の二点を押さえる必要があります。
- テストケース毎にtransactionが張られて、テストが終わるとrollbackされる (参考:Railsテスティングガイド)
-
create_fixtures
で作られたfixtureはテーブル毎にキャッシュされる
キャッシュされたfixtureと同じテーブルに対して、再度fixtureを当てようとしてもDBアクセスは起きません。fixtureのキャッシュはテーブル名(第二引数で渡したfixture_files
の要素)で行われるため、たとえ別のfixture_directory
の同名のfixtureを当てようとしても何も起きません。
何が起きたのか
今回のケースでは、まずFirstTest
クラスでfixtureが当てられます。次に、SecondTest
クラスでもfixtureを当てようとするのですが、fixtureのキャッシュがあるため何も起きません。fixtureは当てられないのですが、FirstTest
クラスのfixtureの内容はrollbackされてDBから消えます。
そのため、some test 2
でTableClass
テーブルの中身を見ても空だったのです。
どうすればよかったのか
FirstClass
のteardown
でfixtureのキャッシュを消せば、SecondClass
でもfixtureが読み込まれます。
class FirstTest < ActiveSupport::TestCase
setup do
fixture_directory = ''
fixture_files = [:tbl]
fixture_models = { tbl: TableClass }
ActiveRecord::FixtureSet.create_fixtures(fixture_directory, fixture_files, fixture_models, DBClass)
end
teardown
ActiveRecord::FixtureSet.reset_cache
end
test 'some test 1' do
pp TableClass.all #=> [...]
end
end
[参考] ActiveRecord::FixtureSet.create_fixtures
def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
fixture_set_names = Array(fixture_set_names).map(&:to_s)
class_names = ClassCache.new class_names, config
# FIXME: Apparently JK uses this.
connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
fixture_files_to_read = fixture_set_names.reject do |fs_name|
fixture_is_cached?(connection.call, fs_name)
end
if fixture_files_to_read.any?
fixtures_map = read_and_insert(
fixtures_directory,
fixture_files_to_read,
class_names,
connection,
)
cache_fixtures(connection.call, fixtures_map)
end
cached_fixtures(connection.call, fixture_set_names)
end