rspecs for a rails plugin

I have a Rails plugin, which is application independent, but depends on
Rails, to be installed in a Rails app. (I have not yet converted it to a
gem, but plan to eventually, and I'm not sure if that would change the
answer to this question).

I'm having trouble figuring out how to set up rspec on this plugin. The
rspec environment needs to at minimum "auto-load" all the classes in the
plugin itself (as a Rails env would do anyway), and ideally auto-load
Rails too for the couple places in the plugin that depend on Rails
classes. But it shouldn't depend on any _particular_ Rails application,
as this is an independent plugin.

Is there a trick for setting this up fairly simply so rspec will work?
All I've been able to find googling is pretty old instructions/advice
that doesn't seem to work quite right on contemporary Rails 2.x systems.

Surely this is something other people have done? Thanks for any advice.

Jonathan

I have this exact problem. I'm refactoring the Foreigner gem and it
has some dependencies against Rails. I originally took
plugin_test_helper and attempted to make it more rspec compatible
before I realized that I did not need to load the full Rails stack. I
only needed ActiveSupport, ActiveRecord, and ActiveRecord::Migration
to run my tests. I have those things loaded in the environment.

You might want to check out plugin_test_helper to see how it gives you
callbacks to patch into the environment and initialization process,
and setting up different kinds of fake rails root.

Ho-Sheng Hsiao

Ho-Sheng Hsiao wrote:

You might want to check out plugin_test_helper to see how it gives you
callbacks to patch into the environment and initialization process,
and setting up different kinds of fake rails root.

Thanks for the pointer to plugin_test_helper, I will try that. Somehow
my googling hadn't come up with it.

Ho-Sheng, is this actually working for you? You are having success
with plugin_test_helper and rspec and a rails plugin?

Ho-Sheng Hsiao wrote:

I have this exact problem. I'm refactoring the Foreigner gem and it
has some dependencies against Rails. I originally took
plugin_test_helper and attempted to make it more rspec compatible
before I realized that I did not need to load the full Rails stack. I
only needed ActiveSupport, ActiveRecord, and ActiveRecord::Migration
to run my tests. I have those things loaded in the environment.

Ah, I see you are not actually using plugin_test_helper, on a re-read.

Can you explain what you mean by "I have those things loaded in the
environment". You load them in the environment how? We're not talking
"Rails app environment", because there is none in your tests of the
plugin, right?

So are you just specifically loading the parts of Rails you need loaded
in tests in your test code? require rubygems, require active-support?
Or something else?

Without Rails there, my _own_ classes don't seem to autoload, like they
do in Rails. How are you loading all your own classes in so classes that
reference each other can be tested? Even if I wanted to just "require"
each one, one by one -- circular dependencies seem to cause a problem
with that. Which the Rails autoloader somehow gets around, but I don't
know how to do it myself for testing without Rails.

Ah, I see you are not actually using plugin_test_helper, on a re-read.

Can you explain what you mean by "I have those things loaded in the
environment". You load them in the environment how? We're not talking
"Rails app environment", because there is none in your tests of the
plugin, right?

I think I might have mis-spoken. I'm doing a fork of Foreigner, and
you can see my work in progress at http://github.com/hosh/foreigner/tree/rspec

Since I want to test different database configuration, all I need to
do is push in the connection credentials. I actually patterned this
off of an old version of acts_as_soft_deleteable (which, IMO, should
be deleted as an evolutionary dead-end). Unlike David Wilkie, I chose
to metaprogram anonymous migrations, so that the tests are easier to
read (see how I did it in http://github.com/hosh/foreigner/blob/rspec/spec/adapter_helper.rb
). Because of that, I don't actually need to use plugin_test_helper to
create a fake app path and manage the library loads (the migrations
are embedded inside the spec where it is easier to follow along what
is being tested).

What you are trying to do might require more. So what *are* you trying
to do?

So are you just specifically loading the parts of Rails you need loaded
in tests in your test code? require rubygems, require active-support?
Or something else?

Yes. See http://github.com/hosh/foreigner/blob/rspec/spec/spec_helper.rb

It is manageable like that for now. I imagine if I needed more, I'd
write a lot more helpers to do that. The main thing, though, is that I
only need a fraction of Rails stack and I only want to test against a
fraction of the Rails stack. Your mileage may vary.

Without Rails there, my _own_ classes don't seem to autoload, like they
do in Rails. How are you loading all your own classes in so classes that
reference each other can be tested? Even if I wanted to just "require"
each one, one by one -- circular dependencies seem to cause a problem
with that. Which the Rails autoloader somehow gets around, but I don't
know how to do it myself for testing without Rails.

I don't have that many classes, so I'm explicitly declaring it. This
is a very common pattern in most of the plugins and gems I've seen.
However, if you want to see how autoloading is done right, look at the
Merb-more gems and the Rails 3 gems. They have awesome examples of how
to organize the autoloading.

Ho-Sheng Hsiao
http://hosheng.blogspot.com

Thanks Ho-Sheng, that helps.

I think I'm actually getting there, starting with the
plugin_test_helper, but modifying it for Rspec, as you had done. It's
not THAT hard, and maybe once I fully figure it out, I'll try to submit
it back to plugin_test_helper. (I don't know how I couldn't find
plugin_test_helper in my own googling, showing me that was incredibly
valuable thanks!)

The one thing I'm still definitely still not getting to work right is
auto-loading of classes. Maybe because "RAILS_ROOT" for the
plugin_test_helper ends up being my_plugin/spec/app_helper -- but my
classes are all in my_plugin/lib and my_plugin/app and such places.

Maybe I can get around this just by setting the Rails load_paths in my
spec_helper.rb? Does that make sense? I wonder how the ordinary
Test::Unit version of plugin_test_helper handles that, it seems like it
would be a problem for it too? [Just resetting RAILS_ROOT to be
something else does NOT work, because of all the bootstrap code in
my_plugin/spec/app_helper that is the whole point and DOES need to be in
RAILS_ROOT].

What I'm doing: My plugin actually DOESN'T use ActiveRecord (yet). In
fact it doesn't use _very_ much of Rails at all, but does use a _bit_
here and there (a couple views you can use in your app if you like).
But even without testing the Rails functionality, the lack of
auto-loading immediately tripped me up. And then I realized that if I
wanted to test the tiny bit of AR functionality that is in there, THAT
was going to trip me up when I got to it.

And really, in general, I'm going to be writing several plug-ins. I want
to figure out something that will Just Work for a Rails plugin, so I
don't _need_ to think about _exactly_ what the dependencies are each
time (and as the app changes), I can just set it up with a "Rails test
environment" and write my tests, and go. I need test running to be as
easy as possible so I will actually write them. :slight_smile: So I think
something based on plugin_test_helper, retrofitted for spec instead of
Test::Unit, is indeed the key to that -- if I can just figure out the
right way to get autoloading working!

I think I'm actually getting there, starting with the
plugin_test_helper, but modifying it for Rspec, as you had done. It's
not THAT hard, and maybe once I fully figure it out, I'll try to submit
it back to plugin_test_helper. (I don't know how I couldn't find
plugin_test_helper in my own googling, showing me that was incredibly
valuable thanks!)

No problem. You let me know if you get the rspec version of it pushed
back out, maybe plugin_spec_helper or something :wink: I'll probably have
a use for it down the road too.

The one thing I'm still definitely still not getting to work right is
auto-loading of classes. Maybe because "RAILS_ROOT" for the
plugin_test_helper ends up being my_plugin/spec/app_helper -- but my
classes are all in my_plugin/lib and my_plugin/app and such places.

I don't know if you've seen this: http://railsguts.com/initialization.html

Browsing through the plugin_test_helper code, they have some hooks to
modify that initialization process, so that might be a way.

Ho-Sheng Hsiao
http://hosheng.blogspot.com

Ho-Sheng Hsiao wrote:

The one thing I'm still definitely still not getting to work right is
auto-loading of classes. Maybe because "RAILS_ROOT" for the
plugin_test_helper ends up being my_plugin/spec/app_helper -- but my
classes are all in my_plugin/lib and my_plugin/app and such places.

I don't know if you've seen this:
http://railsguts.com/initialization.html

Browsing through the plugin_test_helper code, they have some hooks to
modify that initialization process, so that might be a way.

The question is why the plugin_test_helper code hooking into the
initialization process isn't actually _working_ to autoload the classes
in my plugin! Well, I guess I can poor through the code. It's odd to
me, because I wouldn't think switching out Test::Unit for rspec should
effect that at ALL, I can't figure out how this works for anyone if it's
not working for me.

Oh well, that's why they call it debugging I guess. [I just want to get
to _writing my code and tests_, not be spending all this time on
infrastructure! Still surprised that this isn't a common problem someone
else has already solved.]