Как протестировать ElasticSearch в приложении Rails (Rspec) - PullRequest
43 голосов
/ 13 марта 2012

Мне было интересно, как вы тестировали поиск в своем приложении при использовании ElasticSearch и Tire.

  • Как настроить новый тестовый экземпляр ElasticSearch? Есть ли способ издеваться над этим?

  • Любые известные вам драгоценные камни могут помочь с этим?


Некоторые вещи, которые я нашел полезными:

Я нашел отличную статью, отвечающую практически на все мои вопросы:)

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

Плюс, есть ответ от Карми, автора шин.

Это также полезно: https://github.com/karmi/tire/wiki/Integration-Testing-Rails-Models-with-Tire

Не могу поверить, что не нашел их, прежде чем спросить ...

Ответы [ 3 ]

34 голосов
/ 14 марта 2012

Префикс ваших имен индексов для текущей среды

Вы можете установить разные индексы для каждой среды (в вашем случае: тестовая среда).

Например, вы можете создать инициализатор в

config/initializers/tire.rb

со следующей строкой:

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

Возможный подход к удалению индексов

Предполагая, что у вас есть модели с именами «Клиент», «Заказ» и «Продукт», поместите следующий код где-нибудь в своем тестовом запуске / перед блоком / каждый запуск блока.

# iterate over the model types
# there are also ways to fetch all model classes of the rails app automaticly, e.g.:
#   /535763/est-li-sposob-poluchit-kollektsiy-vseh-modelei-v-vashem-prilozhenii-rails
[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. В вашем enviornment / test.rb вы можете установить

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

И в подходящем месте (например, при запуске тестирования) вы можете затем удалить все индексы в экземпляре тестирования ElasticSearch с помощью:

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

Может быть, вы все равно должны убедиться, что ваши определения Tire-Mapping для классов вашей модели все еще вызывают.

11 голосов
/ 04 мая 2012

Я столкнулся со странной ошибкой при удалении индекса эластичного поиска через шину в моем наборе rspec. В моей конфигурации Rspec, похожей на блог Bits and Bytes, у меня есть вызов after_each, который очищает базу данных и стирает индекс.

Я обнаружил, что мне нужно вызвать метод Tire create_elasticsearch_index, который отвечает за чтение отображения в классе ActiveRecord, чтобы настроить соответствующие анализаторы и т. Д. Проблема, с которой я столкнулся, заключалась в том, что в моей модели было несколько полей not_analyzed, которые на самом деле были анализируемый (это сломало то, как я хотел, чтобы гранение работало).

В dev все было нормально, но набор тестов не удался, так как грани разбивались по отдельным словам, а не по всей строке из нескольких слов. Похоже, что конфигурация сопоставления не была создана должным образом в rspec после удаления индекса. Добавление вызова create_elasticsearch_index устранило проблему:

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

Медиа - мой модельный класс.

4 голосов
/ 02 марта 2013

Я столкнулся с похожими проблемами, и вот как я решил это. Не забывайте, что мое решение основано на решении @spaudanjo. Поскольку я использую spork, я добавляю это в блок spec_helper.rb Spork.each_run, но вы можете добавить это в любой другой блок / 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. Результатом будет имя вашего проекта.

...