web-dev-qa-db-ja.com

Railsアプリケーション(Rspec)でElasticSearchをテストする方法

ElasticSearchとTireを使用するときに、アプリケーションで検索をどのようにテストしていたのかと思いました。

  • 新しいElasticSearchテストインスタンスはどのようにセットアップしますか?それをあざける方法はありますか?

  • あなたがそれを知っている宝石はそれを助けるかもしれませんか?


私が役に立ったと思ったもの:

私は私の質問のほとんどすべてに答える素晴らしい記事を見つけました:)

http://bitsandbit.es/post/11295134047/unit-testing-with-tire-and-elastic-search#disqus_thread

さらに、タイヤの作者であるKarmiからの回答があります。

これも便利です: https://github.com/karmi/tire/wiki/Integration-Testing-Rails-Models-with-Tire

質問する前にこれらが見つからなかったなんて信じられません...

43
Robin

現在の環境のインデックス名のプレフィックス

環境ごとに異なるインデックス名を設定できます(あなたの場合:テスト環境)。

たとえば、次のようにイニシャライザを作成できます。

config/initializers/tire.rb

次の行で:

Tire::Model::Search.index_prefix "#{Rails.application.class.parent_name.downcase}_#{Rails.env.to_s.downcase}"

インデックスを削除するための考えられるアプローチ

Customer、Order、Productという名前のモデルがあると想定して、次のコードをtest-startup/before-block/each-run-blockのどこかに配置します。

# iterate over the model types
# there are also ways to fetch all model classes of the Rails app automaticly, e.g.:
#   http://stackoverflow.com/questions/516579/is-there-a-way-to-get-a-collection-of-all-the-models-in-your-Rails-app
[Customer, Order, Product].each do |klass|

  # make sure that the current model is using tire
  if klass.respond_to? :tire
    # delete the index for the current model
    klass.tire.index.delete

    # the mapping definition must get executed again. for that, we reload the model class.
    load File.expand_path("../../app/models/#{klass.name.downcase}.rb", __FILE__)

  end
end

オルタナティブ

別の方法として、別のポートでテストするために別のElasticSearchインスタンスを設定することもできます。たとえば、1234とします。環境/test.rbでは、次のように設定できます。

Tire::Configuration.url "http://localhost:1234"

そして、適切な場所(テストのスタートアップなど)で、ElasticSearch Testing-instanceのすべてのインデックスを削除できます。

Tire::Configuration.client.delete(Tire::Configuration.url)

たぶん、モデルクラスのTire-Mapping定義がまだ呼び出されていることを確認する必要があります。

34
spaudanjo

私のrspecスイートでタイヤ経由でelasticsearchインデックスを削除すると、風変わりなバグに遭遇しました。私のRspec構成では、Bits and Bytesブログと同様に、データベースをクリーンアップしてインデックスを消去するafter_each呼び出しがあります。

適切なアナライザーなどをセットアップするためにActiveRecordクラスのマッピングを読み取る責任があるTireのcreate_elasticsearch_indexメソッドを呼び出す必要があることがわかりました。これは私がファセットを機能させたかった方法を破りました)。

開発ではすべて問題ありませんでしたが、ファセットが複数のWord文字列全体ではなく個々の単語で分解されていたため、テストスイートは失敗しました。インデックスが削除された後、マッピング設定がrspecで適切に作成されていなかったようです。 create_elasticsearch_index呼び出しを追加すると、問題が修正されました。

config.after(:each) do
  DatabaseCleaner.clean
  Media.tire.index.delete
  Media.tire.create_elasticsearch_index
end

メディアは私のモデルクラスです。

11
mhamrah

私は同様の問題に遭遇しました、そしてここに私がそれを解決した方法があります。私のソリューションは@spaudanjoソリューションの上に構築されていることに注意してください。私はsporkを使用しているので、これをspec_helper.rbSpork.each_runブロック内に追加しますが、他のeach/beforeブロックに追加できます。

# Define random prefix to prevent indexes from clashing
Tire::Model::Search.index_prefix "#{Rails.application.class.parent_name.downcase}_#{Rails.env.to_s.downcase}_#{Rand(1000000)}"

# In order to know what all of the models are, we need to load all of them
Dir["#{Rails.root}/app/models/**/*.rb"].each do |model|
  load model
end

# Refresh Elastic Search indexes
# NOTE: relies on all app/models/**/*.rb to be loaded
models = ActiveRecord::Base.subclasses.collect { |type| type.name }.sort
models.each do |klass|
  # make sure that the current model is using tire
  if klass.respond_to? :tire
    # delete the index for the current model
    klass.tire.index.delete

    # the mapping definition must get executed again. for that, we reload the model class.
    load File.expand_path("../../app/models/#{klass.name.downcase}.rb", __FILE__)
  end
end

基本的には、すべてのテストケースに対して独自の一意のプレフィックスを定義するため、インデックス内に存在しません。他のソリューションはすべて、インデックスを削除した後でも、Elastic Searchがインデックスを更新しない(Model.index.refreshを実行した後でも)ため、ランダム化されたプレフィックスが存在するという問題に悩まされていました。

また、すべてのモデルをロードし、tireに応答するかどうかをチェックするため、spec_helper.rbと他の領域の両方でタイヤに応答するすべてのモデルのリストを維持する必要がなくなります。

この方法では、使用後にインデックスが「削除」されないため、定期的に手動で削除する必要があります。これが大きな問題になるとは思いませんが、次のコマンドで削除できます。

curl -XDELETE 'http://localhost:9200/YOURRAILSNAMEHERE_test_*/'

YOURRAILSNAMEHEREを見つけるには、Rails consoleを実行し、Rails.application.class.parent_name.downcaseを実行します。出力はプロジェクトの名前になります。

4
Hengjie