Rails Engine Testing with RSpec, Capybara, and FactoryGirl

UPDATED: I've updated the instructions based on feedback in the comments suggesting the use of the --dummy-path=spec/dummy --skip-test-unit options on the rails plugin new command.

Recently, we've been doing a lot more with Rails engines. We've developed a few engines that we've released publicly, and even more that we use privately on applications. We've found it's a good way to organize and share reusable code across a number of applications.

We really like using RSpec, Capybara, and FactoryGirl to test our Rails applications, and we like to use them to test our engines too. Here's a few steps to get your new engine up and running with these gems in no time:

  1. Run rails plugin new ENGINE_NAME --dummy-path=spec/dummy --skip-test-unit --full or rails plugin new ENGINE_NAME --dummy-path=spec/dummy --skip-test-unit --mountable. This is a good discussion of why you'd choose mountable or full engines.
  2. Add these lines to the gemspec file:

    s.add_development_dependency 'rspec-rails'
    s.add_development_dependency 'capybara'
    s.add_development_dependency 'factory_girl_rails'
  3. Add this line to your gemspec file:

    s.test_files = Dir["spec/**/*"]
  4. Modify Rakefile to look like this:

    #!/usr/bin/env rake
     require 'bundler/setup'
    rescue LoadError
     puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
    APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
    load 'rails/tasks/engine.rake'
    Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
    require 'rspec/core'
    require 'rspec/core/rake_task'
    desc "Run all specs in spec directory (excluding plugin specs)"
    RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
    task :default => :spec

    This will setup your Rakefile to run your specs and make that the default task. It will also setup the specs to reload the test database just like how it works inside a Rails application.

  5. Create a spec/spec_helper.rb file:

    ENV['RAILS_ENV'] ||= 'test'
    require File.expand_path("../dummy/config/environment.rb", __FILE__)
    require 'rspec/rails'
    require 'rspec/autorun'
    require 'factory_girl_rails'
    # Load support files
    Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
    RSpec.configure do |config|
     config.mock_with :rspec
     config.use_transactional_fixtures = true
     config.infer_base_class_for_anonymous_controllers = false
     config.order = "random"

    This code requires all the gems you need for writing your specs, loads the dummy application, and configures RSpec.

  6. Finally, add this config to your engine file (lives at lib/my_engine/engine.rb):

    module MyEngine
     class Engine < ::Rails::Engine
     config.generators do |g|
     g.test_framework :rspec, :fixture => false
     g.fixture_replacement :factory_girl, :dir => 'spec/factories'
     g.assets false
     g.helper false

    Here, we're telling Rails when generating models, controllers, etc. for your engine to use RSpec and FactoryGirl, instead of the default of Test::Unit and fixtures

After this, you can start writing specs with FactoryGirl factories and integration specs (inside the spec/features directory) with Capybara. Have fun testing!

Brian Landau

Brian Landau