Testing your rails plugin within a full Ruby on Rails stack

If you're interested in Ruby on Rails plugins development you have certainly faced some problems to setup a test environment.
The first step is provided by script/generate plugin which creates a new plugin directory (inside vendor/plugin) with a barebone plugin skeleton, including a test case and its helper.
This is enough to start coding but not enough if you need to rely upon some rails application usual components (at least models).
The first solution is to bloat the plugin test helper with tables definitions and models definitions but even if sufficient where do you put helpers ? controllers ? views ? Sooner or later you'll need to put the real pieces of a Rails application together (models, controllers, views, locales, ...) and you'll have two options (AFAIK) :
1) develop your plugin inside an empty rails application (an application used only for development and testing purposes).
The problem is that your happy plugin users will never be able to test your plugin because they will not have the entire app, as long as they install your plugin the usual way : script/install plugin
2) ship your plugin with an independent rails app skeleton that will totally isolate your plugin from the outside world

Setting this enviroment proved to be less difficult than I though, with the help of few tricks lying around the web.

1) script/generate plugin my_plugin
2) cd vendor/plugins/my_plugin/test
3) rails test_rails
4) edit test/test_helper

ENV['RAILS_ENV'] = 'test'
test_rails = File.dirname(__FILE__) + '/test_rails'
require 'test/unit'
require "#{test_rails}/config/environment.rb"
require 'active_support/test_case'
require 'rubygems'
ActiveRecord::Migration.verbose = false
load(File.join(test_rails, "db", "schema.rb"))

5) edit test_rails/config/environment.rb and add config.plugin_paths , eg

RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION

require File.join(File.dirname(__FILE__), 'boot')

Rails::Initializer.run do |config|
config.plugin_paths = ["#{RAILS_ROOT}/../../../"]
config.i18n.default_locale = :fr
config.i18n.locale = :fr
end

6) database

By default sqlite3 is used which is perfect for us - so config/databases.yml must contains at least

test:
adapter: sqlite3
dbfile: db/test.sqlite3
timeout: 5000

7) edit test_rails/config/enviroments/test.rb (you can even delete production.rb and development.rb files)

config.cache_classes = false
config.whiny_nils = true
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_controller.allow_forgery_protection = false
config.action_mailer.delivery_method = :test
config.log_level = :debug
config.whiny_nils = true

The cache_class setting prevents rails from preloading your models classes at startup, which will fail if your plugin extends ActiveRecord (an acts_as_something) because at startup time the plugin is not yet loaded.

7) delete all files under rails_test/test

8) put the stuff needed to test your plugin : models in app/models, view in app/views and so on.

9) edit rails_test/db/schema.rb and define so tables

eg.

ActiveRecord::Schema.define(:version => 0) do

create_table :foos, :force => true do |t|
t.date :a_date
t.datetime :a_datetime
t.time :a_time
end

end

10) you're done !

cd my_plugin/test

edit my_plugin_test.rb and write some tests

rake test

 

Finale notice : This setup worked for me, maybe it won't for you ! You could have to investigate Rails initializer code and change config options accordingly.