How do I prepare test database(s) for Rails rspec tests without running rake spec?

后端 未结 6 1785
無奈伤痛
無奈伤痛 2020-12-04 14:28

After significant troubleshooting, I figured out that I needed to run rake spec once (I can abort with control-c) before I can run rspec directly (e.g. on a sub

6条回答
  •  没有蜡笔的小新
    2020-12-04 14:57

    The provided solutions all require to load the Rails environment, which is, in most cases, not the desired behaviour due to very large overhead and very low speed. DatabaseCleaner gem is also rather slow, and it adds another dependency to your app.

    After months of chagrin and vexation thanks to reasons vide supra, I have finally found the following solution to be exactly what I need. It's nice, simple and fast. In spec_helper.rb:

    config.after :all do
      ActiveRecord::Base.subclasses.each(&:delete_all)
    end
    

    The best part about this is: It will only clear those tables that you have effectively touched (untouched Models will not be loaded and thus not appear in subclasses, also the reason why this doesn't work before tests). Also, it executes after the tests, so the (hopefully) green dots will appear right away.

    The only downside to this is that if you have a dirty database before running tests, it will not be cleaned. But I doubt that is a major issue, since the test database is usually not touched from outside tests.

    Edit

    Seeing as this answer has gained some popularity, I wanted to edit it for completeness: if you want to clear all tables, even the ones not touched, you should be able to do something like the "hacks" below.

    Hack 1 - pre-loading all models for subclasses method

    Evaluate this before calling subclasses:

    Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))
    

    Note that this method may take some time!

    Hack 2 - manually truncating the tables

    ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }
    

    will get you all table names, with those you can do something like:

    case ActiveRecord::Base.configurations[Rails.env]["adapter"]
    when /^mysql/, /^postgresql/
      ActiveRecord::Base.connection.execute("TRUNCATE #{table_name}")
    when /^sqlite/
      ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}")
      ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table_name}'")
    end
    

提交回复
热议问题