
RSpec and Cucumber by default are setup to work with relational databases using ActiveRecord. This has been fine for the most part until so many NoSQL databases have come onto the scene. Let’s focus on getting Cucumber and RSpec working with MongoDB using Mongoid.
First you will need to setup your Rails 3 application to use Mongoid, Cucumber, RSpec, and Factory Girl. Once you have a project skeleton, you will need to setup RSpec to drop all the MongoDB collections of the project before each spec is run to ensure a clean test harness.
The best command to drop your MongoDB collections comes from Mongoid creator Durran Jordan in Mongoid’s code base:
Mongoid.master.collections.select {|c| c.name !~ /system/ }.each(&:drop)
RSpec
Here is a sample RSpec configuration which will empty your MongoDB db and also use Factory Girl to create your models. Note that config.user_transactional_fixtures is commented out.
# spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'remarkable/active_model'
require 'remarkable/mongoid'
require 'factory_girl'
# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, comment the following line or assign false
# instead of true.
# config.use_transactional_fixtures = true
config.before :each do
Mongoid.master.collections.select {|c| c.name !~ /system/ }.each(&:drop)
end
end
Cucumber
Cucumber allows defining hooks in any file under the features/support directory. To begin setting up Cucumber, first create a file features/support/hooks.rb that will drop your MongoDB collections before each scenario.
# features/support/hooks.rb
Before do |scenario|
Mongoid.master.collections.select {|c| c.name !~ /system/ }.each(&:drop)
end
I also find that using Factory Girl for my Cucumber scenarios makes my life a lot easier. Below is an example features/support/env.rb file which will import all your factories. It will also provide some already defined step definitions by the guys at thoughtbot. Be sure to read about them in their post gimme three steps.
# env.rb
ENV["RAILS_ENV"] ||= "test"
require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
require 'cucumber/formatter/unicode'
require 'cucumber/rails/rspec'
require 'cucumber/rails/world'
require 'cucumber/web/tableish'
require 'capybara/rails'
require 'capybara/cucumber'
require 'capybara/session'
require 'cucumber/rails/capybara_javascript_emulation'
Capybara.default_selector = :css
ActionController::Base.allow_rescue = false
require 'factory_girl'
require 'factory_girl/step_definitions'
Dir[File.expand_path(File.join(File.dirname(__FILE__),'..','..',
'spec','factories','*.rb'))].each {|f| require f}
All the step definitions from factory_girl/step_definitions work except for “create record & set one attribute”:
Given an author exists with an email of "author@example.com"
The reason for this is because in the Factory girl code, theere is a check that determines if the given model responds to :columns. To get around this, add the following code to a new file features/step_definitions/mongoid_steps.rb:
# features/step_definitions/mongoid_steps.rb
Given /^an? (.+) exists with an? (.+) of "([^"]*)"$/ do |model, field, value|
factory_name = model.gsub(' ', '_')
Factory factory_name, field => value
end
The last thing to do is stub out the rake task for db:test:prepare. The Cucumber rake tasks are still dependent on the ActiveRecord test workflow and will attempt to load the db schema into the test db. Create the file lib/tasks/mongo.rake to get around this:
Update: As of version 2.0.0.beta.14 of mongoid, a stubbed rake task for db:test:clone is included.
# lib/tasks/mongo.rake
namespace :db do
namespace :test do
task :prepare do
# Stub out for MongoDB
end
end
end
Finally, if you don’t want to do this everytime you setup an application, I’ve updated rails-templater to do the above steps automatically.




View Comments
Hi Kevin
I tried to get it running , using all your recommandations ( see git://gist.github.com/495473.git ) but cucumber put my scenario undefined :
Given /^a minimal_user exists$/ do
pending # express the regexp above with the code you wish you had
end
I thought the step definition was defined in Factory_girl/step_definitions ? or it's not loaded ? where am I wrong .. or missing some important point ?
The issue you are experiencing is that the model name must be a human name. Basically remove the underscore and you should be good to go:
Ex.
Given a minimal user exists
I will update this post to use the above usage in the custom step as well.