Testing Rails Engine Gems
I've been working on a number of gems that are basically packaged Ruby on Rails engine plugins. It turns out that turning gems into plugins is pretty easy to do. However, testing them can be a pain. Here are a few things I came up with.
After looking at how Clearance handles tests I've decided that it's ok to embed a basic Rails application in your test directory.
The next trick is getting the gem you are working on to load in your embedded Rails application. The Clearance guys added a file in config/initializers that looks like this:
# This simulates loading the clearance gem, but without relying on # vendor/gems clearance_path = File.join(File.dirname(__FILE__), *%w(.. .. .. ..)) clearance_lib_path = File.join(clearance_path, "lib") $LOAD_PATH.unshift(clearance_lib_path) load File.join(clearance_path, 'rails', 'init.rb')
I thought that was brilliant but it didn't work for me. After messing around in the Rails code for a bit I found a bit of helpful documentation on 'plugin_locators':
The classes that handle finding the desired plugins that you‘d like to load for your application. By default it is the Rails::Plugin::FileSystemLocator which finds plugins to load in vendor/plugins. You can hook into gem location by subclassing Rails::Plugin::Locator and adding it onto the list of plugin_locators.
That sounded like the perfect solution to my problem. I figured I would simply add a plugin locator that pointed to the root of the gem I was building. Turns out that works great. In the embedded rails application inside of config/environment.rb I added this code:
class TestGemLocator < Rails::Plugin::Locator def plugins Rails::Plugin.new(File.join(File.dirname(__FILE__), *%w(.. .. ..))) end end Rails::Initializer.run do |config| config.time_zone = 'UTC' config.plugin_locators << TestGemLocator end
Now my tests load correctly and all is well. Context is important. If you want to have a look at the full project I put it into a gem called disguise which you can get from github.
Justin Ball is a software consultant and entrepreneur with a passion for Ruby. He evolved from a C++ and .Net monkey into a python programmer and finally found Ruby. In the rare moments when he isn't writing code, talking about code or measuring his code productivity in profanity per hour, you can find him on his bike in the mountains or on the roads surrounding Cache Valley. 










I talked to Yehuda Katz about this method of testing in Rails 3. Turns out you won't need the TestGemLocator any longer. Instead, you'll only need to require your gem so something like
require 'clearance' in application.rb will do the trick.
On a side note Yehuda also mentioned that bundler can load gems from a path so in development it will be possible to point to all of the gem directories you are working on and use those rather than installing each gem and restarting your application.
I talked to Yehuda Katz about this method of testing in Rails 3. Turns out you won't need the TestGemLocator any longer. Instead, you'll only need to require your gem so something like
require 'clearance' in application.rb will do the trick.
On a side note Yehuda also mentioned that bundler can load gems from a path so in development it will be possible to point to all of the gem directories you are working on and use those rather than installing each gem and restarting your application.
I’m a little confused about declaring dependencies within your engine. How can one specify a plugin or gem for the engine itself, rather than having to specify it in the app?
engine testing
Currently you embed an entire Rails application in the test directory and then refer to the code in the gem with
Rails::Plugin.new(File.join(File.dirname(__FILE__), *%w(.. .. ..)))
In Rails 3 you will still embed a test Rails application but you will provide gem bundler with a path to the gem code – File.join(File.dirname(__FILE__), *%w(.. .. ..)) – Then the test app will know where to get it.
If you need an example of how to do it in Rails 2.3.5 you can pull down one of the gems I've built:
http://github.com/tatemae/muck-users
I'll be updating those gems to Rails 3 as soon as it is released.
To test a Rails Engine plugin, you have to embed a full Rails application inside of the plugin's test folder. There are a couple of old tricks for loading the plugin into the embedded Rails app, for testing..