rake specを実行せずにRailsrspecテスト用のテストデータベースを準備するにはどうすればよいですか?


83

重要なトラブルシューティングの後、rake specrspecを直接実行する前に(たとえば、スペックのサブセットで)、一度実行する必要があることがわかりました(control-cで中止できます)。Rails3.0.7とRSpec2.5.0を実行しています。

明らかに、rakeはいくつかの重要なデータベースセットアップタスク/コードを実行しています(ルートレベルのレールRakefileやその他の場所にカスタムコードがあります)。

実行せずにraketestデータベースのセットアップタスク/コードを実行するにはどうすればよいrake specですか?

ファイルのサブセットでrspecを実行できることに加えて、specjourを使用してスペックを複数のコアに分散しています(LAN全体にスペックを分散することはまだ成功していません)が、rspecを実行する場合と同じ動作が見られます直接:rake specspecjourが機能する前に、各テストデータベースで実行する必要があります(2つのコアを想定):

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::Configuration.prepare.specjour / hooks.rbに設定することで、各specjourテストデータベースで任意のコードを実行できると思います。そのため、実行する必要のあるrakeタスクやその他のコードがあれば、そこで機能する可能性があります。

回答:


14

職場でのCIシステムのセットアップでも同様の問題が発生したため、これを処理するシステムを徐々に構築しました。それは最善の解決策ではないかもしれませんが、私の状況ではうまくいき、私は常に物事を行うためのより良い方法を探しています。

セットアップが必要なテストデータベースがありますが、テストを機能させるためにシードデータをロードする必要もありました。

rakeタスクのトラブルシューティングの基本は、-traceオプションを指定してrakeを実行し、内部で何が起こっているかを確認することです。これを行ったとき、rake仕様を実行すると、カスタム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


はい、-traceを使用してrake specを実行し、prepare specjourフックでそのタスクの一部を複製しようとしましたが、まだ機能していません。完全に別のrakeタスクを作成して設定することもできますが、それは避けたいと思っていたもう1つのステップです。
gerry3

169

テストデータベースを削除してから、再作成して移行することをお勧めします。

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

gerry3次のように述べています。

より簡単な解決策は、実行することです rake db:test:prepare

ただし、PostgreSQLを使用している場合は、rails環境が読み込まれ、データベース接続が開かれるため、これは機能しません。これにより、prepareDBをドロップできないため、呼び出しが失敗します。トリッキーなこと。


47
より簡単な解決策は、を実行することrake db:test:prepareです。
gerry3 2012年

7
rake db:test:preparePostgresで問題なく実行できます。他の理由で問題が発生している必要があります。
gerry3 2012

もしDB:テスト:いくつかのタイピングを節約するためにあなたは、少なくともインラインコマンドを置くことができます動作しません準備:RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load
funwhilelost

11
以下のように見えるrake db:test:prepareレール4に廃止されました
markquezada

8
できるのは、このような連鎖すくいタスク:bundle exec rake db:drop db:create db:schema:load RAILS_ENV=test
davegson

14

提供されているソリューションはすべて、Rails環境をロードする必要がありますが、オーバーヘッドが非常に大きく、速度が非常に遅いため、ほとんどの場合、望ましい動作ではありません。DatabaseCleanergemもかなり遅く、アプリに別の依存関係を追加します。

上記の理由による数ヶ月の悔しさと悩みの末、私はついに次の解決策がまさに私が必要としているものであることに気づきました。それは素晴らしく、シンプルで速いです。でspec_helper.rb

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

これについての最良の部分は次のとおりです。効果的に触れたテーブルのみがクリアされます(触れられていないモデルはロードされないsubclassesため、に表示されません。また、テスト前にこれが機能しない理由もあります)。また、テスト後に実行されるため、(うまくいけば)緑色の点がすぐに表示されます。

これの唯一の欠点は、テストを実行する前にダーティデータベースがある場合、データベースがクリーンアップされないことです。しかし、テストデータベースは通常、外部のテストからは影響を受けないため、これが大きな問題であるとは思えません。

編集

この回答がある程度人気を博しているので、完全を期すために編集したいと思いました。触れていないテーブルも含め、すべてのテーブルをクリアたい場合は、以下の「ハック」のようなことができるはずです。

ハック1-すべてのモデルをプリロードする subclassesメソッドのする

呼び出す前にこれを評価してくださいsubclasses

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

この方法には時間がかかる場合があることに注意してください。

ハック2-手動でテーブルを切り捨てる

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

きちんと!これは非常に便利です。
odigity 2013


3

スプリング化されたRails4アプリでbin/setupは、通常、私は次のように拡張されます

puts "\n== Preparing test database =="
system "RAILS_ENV=test bin/rake db:setup"

これは、リヴァイアサンの答えに非常に似ていますが、テストDBをシードします。

rake db:setup #データベースを作成し、スキーマをロードし、シードデータで初期化します
最初にデータベースを削除するためにも使用db:reset します)

コメントが述べているように、最初にDBを削除したい場合は、それを実行rake db:resetします。

また、これはに比べてより多くのフィードバックを提供することもわかりましたrake db:test:prepare


0

テストデータベースを削除することから始めました rake db:drop RAILS_ENV=test

新しいテストデータベースを作成しようとしたときに、ユーザーアカウントがデータベースを所有するアカウントと同じではなかったために問題が発生したため、代わりにPostgreSQLでデータベースを作成しました。

タイプpsql自分以外のアカウントを使用してテスト・データベースを作成するには、以下の実行し、プロンプトとコマンドインチ CREATE DATABASE your_database_name OWNER your_db_owner;

次に、テスト環境で移行を実行します。 rake db:migrate RAILS_ENV=test

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.