Rails Engine Testing with RSpec, Capybara, and FactoryGirl

Brian Landau, Former Developer

Article Category: #Code

Posted on

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
    begin
     require 'bundler/setup'
    rescue LoadError
     puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
    end
    
    APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
    load 'rails/tasks/engine.rake'
    
    Bundler::GemHelper.install_tasks
    
    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'
    
    Rails.backtrace_cleaner.remove_silencers!
    
    # 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"
    end

    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
     end
    
     end
    end

    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!

Related Articles