sporkrb / spork

A DRb server for testing frameworks (RSpec / Cucumber currently) that forks before each run to ensure a clean testing state.
spork.rubyforge.org
MIT License
1.4k stars 202 forks source link

spork + rspec-2 + rails-3 doesn't reload models by default #37

Closed dchelimsky closed 14 years ago

dchelimsky commented 14 years ago

I just got rspec-2 working with spork and rails-3. I haven't had a chance to investigate why yet, but with this configuration we need to set config.cache_classes = false to get models to reload. This suggests that rails is eager loading models during the prefork (which in my case is not asking to load anything under app). Something we can manage from spork?

timcharper commented 14 years ago

Great news. Yes, I'm betting models are getting preloaded. It's a nasty duck punch to make spork do it's magic with Rails, unfortunately. I'm hoping the Rails 3 cleans up it's architecture. I'm dreading figuring out how to get the tests running with Bundler... there's so much uncertainty around it still.

dchelimsky commented 14 years ago

Are you at RC this week?

timcharper commented 14 years ago

No, at home.

petRUShka commented 14 years ago

What should I do to avoid this issue?

If I set config.cache_classes to false I have very many test fails of my apps.

timcharper commented 14 years ago

I pushed spork 0.8.4 out, it includes a patch contributed by Elliot Winkler that fixes the bundler/spork conflict with the diagnoser mode.

Can you run spork -d and see what's preloading it? We must intervene, with the best means available, to make the application not preload the models.

Tim

petRUShka commented 14 years ago

My system: ruby 1.9.3dev (2010-05-08 trunk 27674) [x86_64-linux] spork (0.8.4)

$ spork -d > out.txt

https://gist.github.com/bfb318c6375c444ed395

And my spec_helper: https://gist.github.com/1d92348b08b71a5fc798 I runned spork. Then I added error in my user.rb. I run rspec with --drb and get no error. Then I run rspec without drb and saw an error.

$ rspec spec/models/user_spec.rb --drb
...
Finished in 0.0281 seconds
3 examples, 0 failures
$ rspec spec/models/user_spec.rb
/usr/lib/ruby/gems/svn/gems/activerecord-3.0.0.beta3/lib/active_record/base.rb:1141:in method_missing': undefined methods' for #Class:0x0000000474caa8 (NoMethodError)

thibaudgg commented 14 years ago

same problem that petRUShka with Ruby 1.8.7 & Rails 3.0.0.beta4 (config.cache_classes to false => many test fails) and model modification not reloaded.

my spork -d: http://gist.github.com/435745

dpickett commented 14 years ago

I can confirm this issue with the latest version of REE (2010.02) - model modifications are not reloaded

anlek commented 14 years ago

I have a similar issue, however only some models are reloading. My User model does not reload, but my Order model does... (using REE 2010.02) my spork -d: http://gist.github.com/452989 I'm also using Mongoid instead of ActiveRecord

thibaudgg commented 14 years ago

Any news about the resolution of this problem?

timcharper commented 14 years ago

No, but I did just get the spork cucumber testsuite to work with bundler (as in, it can test with a rails project generated using a bundler gemfile)! This is, in my opinion, a HUGE step forward and has been a primary hold-back rails 3.0 support.

thibaudgg commented 14 years ago

Great to hear that, thk for the update!

timcharper commented 14 years ago

OK... so spork totally isn't compatible with rails 3.0 right now. It's been using the Unknown framework, which basically leaves you on your own to make stuff you want loaded each time is done in an each_run block....

thibaudgg commented 14 years ago

It'll be easy to fix?

MSch commented 14 years ago

For me this solution does reload models: http://github.com/rspec/rspec-core/issues/issue/62/#issue/62/comment/305544

mat813 commented 14 years ago

Same here, the solution on the rspec-core issues works for me too. Would be great now that rails 3.0 is out of the closet that spork worked with it :-)

timcharper commented 14 years ago

All interested parties: try out 0.9.0 RC2. At least the integration tests show that model reloading is occurring.

I've still got some doubts about observers triggering pre-loading of models, and have noticed that mongoid seems to want to eagerload the model universe as well.

Tim

mat813 commented 14 years ago

So, do we have to remove the fix from http://github.com/rspec/rspec-core/issues/issue/62/#issue/62/comment/305544 after we've upgraded to 0.9.0 RC2 ? or else ?

timcharper commented 14 years ago

Hmm, I don't know. Try it and see? (it shouldn't be preloading application files.. although some things may still trigger it).

It seems like it's best to avoid preloading any application files (app// and lib/), but I can see the merit in that being an easy, reliable solution (although it feels a little messy).

... so... you tell me?

mat813 commented 14 years ago

Ok, so, I upgraded to 0.9.0.rc2, removed the fix from the rspec-core issue 62's comment, and I ran the tests once, changed a model so that some tests should fail, and with spork, the model was not reloaded, it was still giving me a all's ok result, restarting spork gives me the errors I was expecting, correcting the model back still gives me the errors. Putting back the fix gives me back the expected result. So, all in all, no, not fixed :-)

timcharper commented 14 years ago

OK :) there's likely something else triggering the models to load during boot. Do you have observers loaded? Can you post the interesting pieces from the result of `spork -d'

mat813 commented 14 years ago

No observers. Here's the spork -d output :

Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
- Spork Diagnosis -
-- Summary --
config/application.rb
config/boot.rb
config/environment.rb
config/environments/test.rb
config/initializers/backtrace_silencers.rb
config/initializers/devise.rb
config/initializers/haml.rb
config/initializers/inflections.rb
config/initializers/mime_types.rb
config/initializers/new_rails_defaults.rb
config/initializers/secret_token.rb
config/initializers/session_store.rb
config/routes.rb
spec/spec_helper.rb
vendor/plugins/dynamic_form/lib/action_view/helpers/dynamic_form.rb
vendor/plugins/jrails/lib/jquery_selector_assertions.rb
vendor/plugins/jrails/lib/jrails.rb
timcharper commented 14 years ago

huh, I'll be. It doesn't show that you're models are being preloaded (scratches head until bald spot occurs)

I'm seriously stumped here.

wakiki commented 14 years ago

I'm also using rspec 2 / Rails 3.0.0 / Spork '0.9.0.rc2' and it is not reloading models either. I can't use the hack above because I'm also using database_cleaner with my Capybara/Selenium Webdriver tests - gives me a wierd TypeMismatch error - somehow the classes are defined twice.

I resorted to doing the following:

Spork.each_run do

This code will be run each time you run your specs.

Force-load all the app files.

Ugly spork hack because it doesn't work with Rails 3 - remove as soon as spork is fixed

silencewarnings do Dir["#{Rails.root}/app/*/_.rb"].each { |f| load f } end end

wakiki commented 14 years ago

spork -d didn't reveal anything but I think I've found out where the models are being preloaded - via factory_girl

I did this by placing the following lines on top of one of my models (person.rb), and then tail'ed the test.log:

begin raise rescue => e Rails.logger.info [e, e.backtrace].join("\n") end

http://pastie.org/private/vheva2yln2qtfywhwrtqw

I wonder if it's possible to trap the method like you do for other things...

Steve

timcharper commented 14 years ago

So weird that it is preloaded but not showing up in your `spork -d'. I'll have to try and play around with a test project and see if I can reproduce here.

Trapping the method seems like the best approach. The find_definitions method looks like the best bet.

Try this:

Spork.trap_class_method(Factory, :find_definitions)

Put it so it gets called before the environment is loaded, and after factory_girl is loaded (you may need to manually require...)

wakiki commented 14 years ago

OK I've figured it out.

It was factory_girl_rails that was causing the preload (which wasn't picked up by spork -d) but it is required as a gem so I moved the gem to its own 'development' only group so it isn't loaded by spork prefork:

group :development do gem 'spork', '0.9.0.rc2' gem 'factory_girl_rails' end

When it comes to spec_helper I manually require it myself (I put all my factories in spec/factories) - you might change that:

Spork.each_run do require 'factory_girl' Dir[File.expandpath(File.join(File.dirname(FILE),'factories','*','_.rb'))].each {|f| require f} end

The models seem to reload properly now.

Cluster444 commented 13 years ago

One problem I had once i finally got spork to reload my models properly was that I could not run a db:reset. I got errors complaining about factory girl not being able to find my database tables, which makes sense since the reset just dropped them!

With the changes in the comment above I no longer needed to load FG within any of the Gemfile groups so i made a separate group that still gets loaded by bundler, but doesn't load FG in any of my environments, leaving spork to load it manually.

group :noload do
  gem 'factory_girl_rails'
end

I'm still not exactly sure what caused db:reset to flip out, but this little hack fixed it.

jgadbois commented 13 years ago

I'm having this same problem with factory girl.

I can't require factory_girl in each_run because I get an error

Exception encountered: #<LoadError: no such file to load -- factory_girl>

Very frustrating. Any suggestions?

Cluster444 commented 13 years ago

https://github.com/Cluster444/zmchapters/blob/74df4d6bb85d3cf25afae028302a6b23d5d07700/spec/spec_helper.rb

https://github.com/Cluster444/zmchapters/blob/74df4d6bb85d3cf25afae028302a6b23d5d07700/Gemfile

That's how i've setup factory girl and it seems to work ok. I've only ever run into a problem with my User model not reloading, the rest of them reload fine.

ozzyaaron commented 13 years ago

Hi there, this is the code I settled on with a co-worker today and it seems to do the trick. Put it in application.rb :

ActionDispatch::Callbacks.after do      
  # Reload the factories
  return unless (Rails.env.development? || Rails.env.test?)

  unless Factory.factories.blank? # first init will load factories, this should only run on subsequent reloads
    Factory.factories.clear
    Factory.find_definitions.each do |location|
      Dir["#{location}/**/*.rb"].each { |file| load file }
    end
  end

end    
nishant-n commented 13 years ago

This is my Spork.prefork block {Spork.prefork do require File.expand_path(File.join(File.dirname(FILE),'..','config','environment')) require 'spec/autorun' require 'ruby-debug' require 'webrat' require 'webrat/integrations/rspec-rails' require 'db/seeds' require 'authlogic/test_case/mock_request' require 'authlogic/test_case/mock_cookie_jar' require 'authlogic/test_case/mock_controller' require 'merchant/utils'
include Merchant::Utils end} when i ran spork -d its only show loaded confin/initializers/..files and spec_helper ......why? is the same issue?

FooBarWidget commented 13 years ago

I've written a wiki entry on this: https://github.com/timcharper/spork/wiki/Troubleshooting

jc00ke commented 13 years ago

I can verify that the suggestion in the wiki does not solve the problem with FactoryGirl 2.1.0 & Rails 3.1. I found it necessary to reload all the models, otherwise changes would not be picked up.

Spork.each_run do
  require 'factory_girl_rails'
  # reload all the models
  Dir["#{Rails.root}/app/models/**/*.rb"].each do |model|
    load model
  end
end

I'll update the wiki article now.

morr commented 13 years ago

I found it necessary to reload all the models, otherwise changes would not be picked up.

This solution works but I'm getting a lot of warnings on every test run because i have constants defined in my models

/home/morr/develop/site/app/models/group_join_policy.rb:2: warning: already initialized constant Free /home/morr/develop/site/app/models/group_join_policy.rb:7: warning: already initialized constant ByOwnerInvite

timcharper commented 13 years ago

The problem is the models are getting preloaded. Spork states that any code that is preloaded will be cached from run to run. Use spork -d | less to get a report of what files are loaded, and a stack trace of what was responsible for triggering the load.

mmriis commented 12 years ago

I just :

Spork.each_run do
  require 'factory_girl_rails'
end

And in my Gemfile :

gem 'factory_girl_rails', :require => false
dtuite commented 12 years ago

+1 on @jc00ke 's last comment. I tried everything else in this thread to no avail on Rails 3.1.1 with FactoryGirl. I have to explicitly reload all the models.

When I run spork -d | less it doesn't say that it's loading app/models prefork.

Finally, once I add foreman or guard into the mix, event @jc00ke 's advice doesn't fix the issue :-(

evanrmurphy commented 12 years ago

I also rely on a workaround like wakiki and jc00ke's to make models reload with spork:

Spork.each_run do
  ...
  # Hack to ensure models get reloaded by Spork - remove as soon as this is fixed in Spork.
  # Silence warnings to avoid all the 'warning: already initialized constant' messages that
  # appear for constants defined in the models.
  silence_warnings do
    Dir["#{Rails.root}/app/models/**/*.rb"].each {|f| load f}
  end
end

Edit: got silence_warnings to work

apux commented 12 years ago

Is this issue solved?, I'm using 1.0.0rc and get the same behavior.

apux commented 12 years ago

Ok, I switched to fork-rails and it works now.