Testing Sunspot with Cucumber

I've been using Sunspot as my full-text search provider for a few months now. It's a very enjoyable library -- it hooks itself into Rails, provides an extension to disable itself in RSpec and even throws in a few convenient rake tasks. This fun came to a quick end, though, when I started delving into Cucumber again. Any feature involving finding a Sunspot-enabled item failed completely, but without any helpful errors. After a shameful amount of time banging my head against the desk, I finally got everyone to play nicely.

The Code

Let's just drop the code in and discuss it afterwards:

# config/sunspot.yml
# copy the test settings into the cucumber environment
test: &TEST
  solr:
    hostname: localhost
    port: 8981
    log_level: WARNING

cucumber:
  <<: *TEST

# features/support/config.rb
# start the Solr server and give it a few seconds to initialize
Sunspot::Rails::Server.start
sleep 5

# make sure that pickle calls #index! on our appropriate models
require File.join(File.dirname(__FILE__), 'pickle')
module Pickle
  module Session
    
    def create_model_with_sunspot(a_model_name, fields = nil)
      result = create_model_without_sunspot(a_model_name, fields)
      
      model = model(a_model_name)
      model.index! if model.respond_to?(:index!)
      
      result
    end
    alias_method_chain :create_model, :sunspot
    
  end
end

# clean out the Solr index after each scenario
After do
  Post.remove_all_from_index!
end

# shut down the Solr server
at_exit do
  Sunspot::Rails::Server.stop
end

The Details

This method was heavily influenced by Brandon Keeper's post on using Cucumber with ThinkingSphinx. Thanks Brandon! So in my setup, I'm using Sunspot, Cucumber and Pickle (see Ryan Bates' railscast on using Pickle with Cucumber for more details on the wonderful Pickle gem).

First and foremost is getting the testing Solr server running. It will look for settings in config/sunspot.yml according to the environment we're running in, so we need to duplicate the test environment for cucumber. I've found that it takes 3-5 seconds for Solr to properly spin up, so we're sleeping for a few seconds to avoid the problem.

Next we need to ensure that each model gets loaded into Solr's index when created. If you're instantiating models on your own, this boils down to calling #index! on any models that you create. Since I'm using Pickle (and didn't want to rework the included pickle_steps.rb), I needed a bit more invasive measure. A bit of alias_method_chain voodoo lets me call #index! on every instantiated model that responds to it. This ensures that Pickle always adds it's models to Solr's index. I was pleased to find that I didn't have to disable transactional fixtures

Finally, we need to ensure that our index is fresh for each scenario, so we clear the Solr index out after each scenario is run. If you want a more targeted approach, you can use

# features/support/config.rb
# clear Solr index only if we've actually used it
After('@sunspot') do
  Post.remove_all_from_index!
end

to only clear the Solr index after stories which are tagged with @sunspot. Once all the stories are run, shut down the server. Viola!

blog comments powered by Disqus