LoginSignup
6
3

[Rails] fixtureが読み込まれない問題

Last updated at Posted at 2023-12-01

まず結論から

setupでfixtureを使う時は、teardownでfixtureのキャッシュを消しましょう。

fixtureが読み込まれない現象

まずは問題のあるコードを掲載します。SecondTestsome 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 2TableClassテーブルの中身を見ても空だったのです。

どうすればよかったのか

FirstClassteardownで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
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3