12. Juli 2013

Disable ElasticSearch-Calls in RSpec Tests

We connect our Rails 3.2 application to ElasticSearch with the famous Tire-Gem. After each save of an indexed object rails calls ElasticSearch via http in sends the new object data. But this behaviour produces quite a lot of overhead in our test suite. In most of the tests we don’t need ElasticSearch and therefore don’t want the objects to be indexed. I found this Gist which mocks ElasticSearch Calls with Webmock. It looks slightly complicated on first sight but works quite fine. The problem is: we also use capybara-webkit for feature tests. And Capybara does HTTP-Calls to the webkit-server. Webmock blocks these requests too. After some research I found a far easier solution: Fakeweb. While Webmock blocks all HTTP calls during the tests, Fakeweb only fakes results on previously defined URLs or URL-patterns. This led me to the following solution:

Add the fakeweb-gem to your Gemfile:

gem 'fakeweb', group :test

Then add the following around-block to your spec_helper.rb, assuming there is one indexed model called Contact:

config.around :each do |example|
  if example.metadata[:elasticsearch]
    Contact.tire.index.delete # delete the index for a clean environment
    example.run
  else
    FakeWeb.register_uri :any, %r(#{Tire::Configuration.url}), body: '{}'
    example.run
    FakeWeb.clean_registry
  end
end

Calls to ElasticSearch are hereby disabled. If you need ElasticSearch to test your searching functionality add the elasticsearch metadata to your tests:

it 'finds a contact', elasticsearch: true do
  contacts = Contact.search('bruce')
  contacts.should include @contact
end

With this solution our tests were about 15-20% faster.