Getting Cucumber, RSpec, and Mongoid to play nice 3

Out of the box, Cucumber is setup to work with Active Record and uses the database_cleaner gem to ensure that the database is clean on each run. database_cleaner does support a few object mappers, but Mongoid is not one of them. It is fairly simple, however, to get a Cucumber and RSpec setup that works with Mongoid, and ensures your test database is clean on each run.

First, if you need help getting Mongoid setup, I recommend you take a look at the documentation on the Mongoid website. That will get you up and running. Before making any other changes, go ahead and run the rspec and cucumber generators for Rails to get the necessary files. Once that is done, make sure that if you’re not using Active Record (and since you’re using Mongoid and MongoDB I’m assuming you’re not unless you have a second database), you exclude it in your config/environment.rb:

config/environment.rb
RAILS_GEM_VERSION = '2.3.5' unless defined? RAILS_GEM_VERSION
require File.join(File.dirname(__FILE__), 'boot')

Rails::Initializer.run do |config|
  config.gem "cucumber"
  config.gem "mongoid"

  config.frameworks -= [ :active_record ]
end

Next we will configure RSpec to clean our database before each spec is run. We can do this by configuring RSpec as follows:

spec/spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))
require 'spec/autorun'
require 'spec/rails'
require 'mongoid'

Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}

Spec::Runner.configure do |config|
  config.before(:each) do
    Mongoid.master.collections.each(&:drop)
  end
end

And, finally, we need to configure Cucumber. I will admit, I had to play around with this for a while to get the correct setup. At one point, I had a situation where my database was only being cleaned correctly every other run. This actually turned out to not be a problem with my configuration, but with my scenarios (I am still somewhat of a Cucumber noob). In a fashion similar to that of our RSpec configuration above, we will simply tell Cucumber to wipe out the collections before each scenario runs:

features/support/env.rb
ENV["RAILS_ENV"] ||= "cucumber"
require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')

require 'cucumber/formatter/unicode'
require 'cucumber/rails/world'
require 'cucumber/web/tableish'
require 'webrat'
require 'webrat/core/matchers'
require 'spec/expectations'
require 'mongoid'

Webrat.configure do |config|
  config.mode = :rails
  config.open_error_files = false
end

Cucumber::Rails::World.use_transactional_fixtures = false

Before do
  Mongoid.master.collections.each(&:drop)
end

I am using “before” hooks on both RSpec and Cucumber. My reasoning behind this is to ensure that when something is running, it starts off with a clean slate. I could easily do an “after” and just have each one clean up after itself, but this way, if I just want to run a single spec or scenario and inspect the data in my test database afterwards, I have that option.

So far learning Cucumber and RSpec has been a great experience and both have really made Behavior Driven Development (BDD) click.

Useful links

3 Comments so far

  1. Grant on March 18th, 2010

    I was just wondering about this in the shower this morning. Thanks for the writeup.

  2. Jon Wood on April 7th, 2010

    Thanks. As ever someone else has attempted this before I did, and was good enough to write about it :)

  3. Kimbro Staken on May 24th, 2010

    Thanks, this was very helpful. It’s a challenge to learn rspec while also using mongodb for the first time.

Leave a Reply