Spork: how to refresh validations and other code?
Asked Answered
S

4

19

I've been using spork all day, and most of the time it is a really great.

However, I am often running into a few problems where I need to restart Spork in order for my tests to pass... and now I'm wondering if it's more trouble than it's worth. I am new at ruby, so sometimes I can't predict if the error is due to a refresh problem, or if the error is due to my unfamiliarity with Ruby and Rails.

What do I need to put into Spork.each_run block so that my validations and other things are refreshed so that I don't have to restart the spork server?

Thanks

Stereopticon answered 2/5, 2011 at 9:37 Comment(0)
F
14

Use Guard to reload Spork when you update your classes Guard::Spork allows to automatically & intelligently start/reload your RSpec/Cucumber Spork server(s).

  1. https://github.com/guard/guard-spork
  2. http://flux88.com/2011/04/using-guard-spork-with-mongoid-devise/
Ferdinana answered 2/5, 2011 at 15:8 Comment(0)
A
15

EDIT: If you can upgrade to Ruby 2.0 this is your best bet. It is fast enough and will let you work in regular way without the need for tools like Spork, Zeus, and ect. And in essence you won't need anything I wrote below.

If you still need some speed bump while developing check out the Fast Rails Commands cast.


Well yes, you want to reload Spork if you changed environment, initializer or spec_helper files (and for that guard-spork is perfect), but not when you updated one of your classes (models) as this would deny the purpose of tools like spork. I had the very same issue: I could delete all methods in a model, and tests would still pass, because Spork hold "old" model class in memory. Restarting Spork was required.

Reason:

Some plugins cause the model code to be preloaded so some work is required to block that from happening.

You want to prevent model code preloaded, as this will not "reload" them if you make any changes (like with validations).

Solutions:

Depends from gems that are involved. In my case, I had to deal with Devise and FactoryGirl, but in essence, you do it by using Spork.trap_method as described on wiki: https://github.com/sporkrb/spork/wiki/Spork.trap_method-Jujitsu

Additionally you can run spork -d to get a list of files that are preloaded, it may be helpful to track which gems may be involved in causing this issue.

Example: Rails 3.0.x + Rspec2 + Spork 0.9.0.rcX + Capybara + Devise + FactoryGirl

# spec/spec_helper.rb
Spork.prefork do
  # This file is copied to spec/ when you run 'rails generate rspec:install'
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'capybara/rspec'
  require 'capybara/rails'

  # set "gem 'factory_girl', :require => false" in Gemfile
  require 'factory_girl'

  # deal with Devise
  require "rails/application"
  Spork.trap_method(Rails::Application, :reload_routes!)

  require File.dirname(__FILE__) + "/../config/environment.rb"

  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

  RSpec.configure do |config|
    config.mock_with :rspec
    config.use_transactional_fixtures = false
    config.before(:suite) do
      DatabaseCleaner.strategy = :transaction
    end
    config.before(:each) do
      DatabaseCleaner.start
    end
    config.after(:each) do
      DatabaseCleaner.clean
    end

    # Devise controller test helpers:
    config.include Devise::TestHelpers, :type => :controller
  end
end

Spork.each_run do
  # deal with factory girl
  Factory.definition_file_paths = [File.join(Rails.root, 'spec', 'factories')]
  Factory.find_definitions
end

Please note that config.cache_classes = true need to be set to true in test environment, otherwise you may get errors from gems like FactoryGirl.

This made my model tests (specs) run quickly, and "reload" them every time I save a file and fire rspec.

EDIT: If you're running on Ruby 1.9.3 you can try out an interesting alternative: Zeus - https://github.com/burke/zeus

Armlet answered 16/7, 2011 at 7:59 Comment(1)
Note that FactoryGirl has changed in FactoryGirl 2. Factory Girl 2 does not have the auto-loading issues of previous versions, so you do not need to do anything to get Spork to work. However, if you want changes to factories to take effect on each run, you can reload them like this (in Factory Girl 2.1 or higher). Spork.each_run do FactoryGirl.reload end See github.com/sporkrb/spork/wiki/Spork.trap_method-JujitsuContractual
F
14

Use Guard to reload Spork when you update your classes Guard::Spork allows to automatically & intelligently start/reload your RSpec/Cucumber Spork server(s).

  1. https://github.com/guard/guard-spork
  2. http://flux88.com/2011/04/using-guard-spork-with-mongoid-devise/
Ferdinana answered 2/5, 2011 at 15:8 Comment(0)
C
3

From http://www.rubyinside.com/how-to-rails-3-and-rspec-2-4336.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+RubyInside+%28Ruby+Inside%29 :

A minor snafu will remain, though. If you update app/models/person.rb, the change won't take effect in your tests since Spork has the old Person still in memory. One way around this is to edit config/environments/test.rb and change:

config.cache_classes = true

To:

config.cache_classes = false
Chalybeate answered 2/5, 2011 at 10:17 Comment(4)
Unfortunately, that still didn't work. I changed the test environment, and then deleted a validation rule (to cause a test to fail), but they all pass. The file still didn't get updated :(Stereopticon
Yeppers :( Could running spork inside of RubyMine have anything to do with it? Let me try on the command line just to be sure.Stereopticon
Yeah, it even passes when it shouldn't on the command line as well.Stereopticon
@Stereopticon Actually cache_classes are better left to true, otherwise one can have strange errors caused by factories like FactoryGirl. As for the issue: usually other gems are involved like Devise or FactoryGirl, but Spork has solution for that too. See comments in mentioned article, and/or this: github.com/timcharper/spork/wiki/Spork.trap_method-JujutsuArmlet
P
2

With more recent versions of Factory Girl, you don't need to do much. First, add FactoryGirl.reload in Spork.each_run. If you have factories with the class parameter, they should be string.

factory :my_model, class: 'MyModel' do...

instead of

factory :my_model, class: MyModel do...

Prang answered 11/1, 2013 at 0:5 Comment(1)
No perceivable slowdown, and considerably simpler than other solutions.Midget

© 2022 - 2024 — McMap. All rights reserved.