重要なトラブルシューティングの後、rspecを直接実行する前に(たとえば、仕様のサブセットで)rake spec
を1回実行する必要があることがわかりました(control-cで中止できます)。 Rails 3.0.7およびRSpec 2.5.0を実行しています。
明らかに、rakeはいくつかの重要なデータベースセットアップタスク/コードを実行しています(ルートレベルにカスタムコードがありますRails Rakefileおよびおそらく他の場所)。
rake spec
?を実行せずに、rakeテストデータベースのセットアップタスク/コードを実行するにはどうすればよいですか?
ファイルのサブセットでrspecを実行できることに加えて、 specjour を使用して仕様を複数のコアに分散しています(まだLANに展開することに成功していません)が、 rspecを直接実行する場合と同じ動作:specjourが機能する前に、各テストデータベースで(2つのコアを想定して)rake spec
を実行する必要があります。
rake spec TEST_ENV_NUMBER=1
control-c (after tests start)
rake spec TEST_ENV_NUMBER=2
control-c (after tests start)
specjour
注:私のconfig/database.ymlには、テスト用の次のエントリがあります(gemの並行テストでは一般的です):
test:
adapter: postgresql
encoding: unicode
database: test<%=ENV['TEST_ENV_NUMBER']%>
username: user
password:
parallel_tests はデータベースを正しくセットアップしているようですが、仕様の多くは失敗しています。
また、specjour prepare
を実行すると、Postgresはデータベースを見つけることができないエラーをログに記録しますが、データベースを作成します(テーブルなし)。後続の実行では、エラーは記録されませんが、テーブルは作成されません。私の問題全体が単にprepare
のバグである可能性があるため、githubで報告しました。
.specjour/hooks.rbでSpecjour::Configuration.prepare
を設定することで、各specjourテストデータベースで任意のコードを実行できると思うので、実行する必要のあるrakeタスクまたは他のコードがある場合、そこで動作する可能性があります。
職場でCIシステムをセットアップする際に同様の問題が発生したため、これを処理するシステムを徐々に作成しました。それは最善の解決策ではないかもしれませんが、それは私の状況では私にとってはうまくいき、私は常により良い方法を探しています。
セットアップが必要なテストデータベースがありますが、テストを機能させるためにシードデータを読み込む必要もありました。
Rakeタスクのトラブルシューティングの基本は、-traceオプションを指定してrakeを実行し、内部で何が起こっているかを確認することです。これを行ったとき、rake specを実行すると、カスタムrakeタスクで複製(または適切と思われる変更)ができることがわかりました。
これが私たちの仕事の例です。
desc "Setup test database - drops, loads schema, migrates and seeds the test db"
task :test_db_setup => [:pre_reqs] do
Rails.env = ENV['Rails_ENV'] = 'test'
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
result = capture_stdout { Rake::Task['db:schema:load'].invoke }
File.open(File.join(ENV['CC_BUILD_ARTIFACTS'] || 'log', 'schema-load.log'), 'w') { |f| f.write(result) }
Rake::Task['db:seed:load'].invoke
ActiveRecord::Base.establish_connection
Rake::Task['db:migrate'].invoke
end
これは単なる例であり、私たちの状況に固有のものです。したがって、テストデータベースをセットアップするために何をする必要があるかを把握する必要がありますが、rakeの--traceオプションを使用して決定するのは非常に簡単です。
さらに、テストのセットアップに時間がかかりすぎる場合(この場合のように)、データベースを.sql形式にダンプし、テストデータベースでmysqlに直接パイプしてロードすることもできます。このようにして、テストデータベースのセットアップから数分節約できます。物事をかなり複雑にしているため、ここではそれを示していません-古くなることなく適切に生成する必要があるなど.
HTH
テストデータベースを削除してから、再作成して移行することをお勧めします。
bundle exec rake db:drop Rails_ENV=test
bundle exec rake db:create Rails_ENV=test
bundle exec rake db:schema:load Rails_ENV=test
これらの手順の後、スペックを実行できます。
bundle exec rspec spec
gerry 次のことに注意してください:
より簡単な解決策は、単に
rake db:test:prepare
ただし、PostgreSQLを使用している場合、Rails環境がロードされ、データベース接続が開かれます。これにより、DBができないためprepare
呼び出しが失敗します。落とします。
提供されるソリューションはすべて、Rails環境をロードする必要があります。これは、ほとんどの場合、非常に大きなオーバーヘッドと非常に低速のため、望ましい動作ではありません。DatabaseCleaner
gemもかなり遅く、アプリに別の依存関係が追加されます。
上記の理由により、数か月にわたる悔しさと悔しさのおかげで、最終的に次の解決策がまさに必要なものであることがわかりました。素晴らしく、シンプルで高速です。 spec_helper.rb
:
config.after :all do
ActiveRecord::Base.subclasses.each(&:delete_all)
end
これについての最良の部分は、あなたが効果的に持っているテーブルのみをクリアしますtouched(未処理のモデルはロードされないため、subclasses
に表示されません。これもそうしない理由です。動作しませんbefore tests)。また、テスト後に実行されるため、(できれば)緑色のドットがすぐに表示されます。
これの唯一の欠点は、テストを実行する前にダーティデータベースがある場合、クリーンアップされないことです。しかし、テストデータベースは通常、外部のテストから影響を受けないため、これは大きな問題ではないと思います。
この答えが人気を博しているのを見て、完全を期すためにそれを編集したいと思いました:allテーブル、触れられていないテーブルでもクリアしたいなら、「ハック」のようなことができるはずです未満。
subclasses
メソッドのすべてのモデルをプリロードするsubclasses
を呼び出す前にこれを評価してください:
Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))
この方法には時間がかかることに注意してください!
ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }
次のようなことができるすべてのテーブル名を取得します:
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
Rails 4.1+では、最良の解決策は単にActiveRecord::Migration.maintain_test_schema!
の後にRails_helperでrequire 'rspec/Rails'
。
つまり、もうデータベースを準備する必要について心配する必要はありません。
https://relishapp.com/rspec/rspec-Rails/docs/upgrade#pending-migration-checks
春に限定されたRails 4アプリでは、私のbin/setup
は通常、
puts "\n== Preparing test database =="
system "Rails_ENV=test bin/rake db:setup"
これは leviathan's answer に非常に似ていますが、テストDBをシードします。
rake db:setup
#データベースを作成し、スキーマをロードし、シードデータで初期化する
(usedb:reset
を使用して、最初にデータベースを削除する)
コメントが言及しているように、DBを最初に削除したい場合、rake db:reset
はまさにそれを行います。
rake db:test:prepare
と比較した場合、これはより多くのフィードバックを提供することもわかりました。