Проблема Spork и cache_classes с rspec, factory_girl и datamapper

#ruby-on-rails #rspec #datamapper #spork #factory-bot

#ruby-on-rails #rspec #datamapper #spork #factory-бот

Вопрос:

У меня проблема с тестовым сервером Spork.

Если я установлю config.cache_classes = false в config / environments /test.rb, то спецификации начнут выдавать ошибки.

 Failure/Error: task = Factory(:something, :foo => @foo, :bar => @bar)
     DataMapper::ImmutableError:
       Immutable resource cannot be modified
  

Это мой spec_helper.rb:

 require 'spork'

Spork.prefork do
  if ENV['CODE_COVERAGE'] == '1'
    require 'simplecov'
    SimpleCov.start 'rails'
  end

  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'webmock/rspec'
  require 'factory_girl'

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

  RSpec.configure do |config|
    config.mock_with :mocha
    config.include Rails.application.routes.url_helpers
    config.include UrlHelper

    config.before(:each) do
      repository(:default) do
        transaction = DataMapper::Transaction.new(repository)
        transaction.begin
        repository.adapter.push_transaction(transaction)
      end
    end

    config.after(:each) do
      repository(:default).adapter.pop_transaction.try(:rollback)
    end

  end
end

# This code will be run each time you run your specs.
Spork.each_run do
  # reload factories
  Factory.definition_file_paths = Dir[File.join(Rails.root, "spec", "factories")]
  Factory.find_definitions

  DatabaseCleaner.strategy = :truncation
  DatabaseCleaner.clean
  LoggedEvent.all.destroy!

end
  

Когда у меня есть config.cache_classes = true, тогда все работает хорошо, но это не перезагружает мне модели, классы контроллеров, поэтому я не вижу смысла в использовании spork в этом случае.

Я пытался добавить в spec_helper.rb что-то вроде этого, когда значение cache равно true:

 Spork.each_run do
    Dir.glob("#{Rails.root}/app/models/*.rb").sort.each { |file| load file }
end
  

Но мне не нравится это решение.

Ответ №1:

Просто добавьте:

 ActiveSupport::Dependencies.clear
  

до конца блока предварительной обработки. это позаботится об очистке моделей.

Кроме того, вы хотите перенести эти включения конфигурации rspec в Spork.each_run, то же самое касается требования поддержки спецификаций и общих файлов.

Это работает, я использую эту настройку в 2 проектах без каких-либо проблем.

Комментарии:

1. Подождите, так ActiveSupport::Dependencies.clear принадлежит prefork или each_run? Я видел противоречивые истории. Ни то, ни другое, похоже, не работает для меня, оба вызывают проблемы с загрузкой: «ожидается, что xxxx определит xxxx». Кроме того, ActiveSupport::Dependencies.clear только ли это решает проблему? Или это необходимо в сочетании с примером each_run в исходном вопросе?

2. Я не знаю почему, но мой проект просто внезапно начал делать это без видимой причины. В итоге я поместил Dependencies.clear в свой Spork.each_run, и у меня это сработало. У меня нет моего Rspec.config в each_run, просто: FactoryGirl.reload и ActiveSupport::Dependencies.clear. Надеюсь, это поможет.

3. ActiveSupport::Dependencies.clear следует добавлять в конце предварительной обработки, а не в each_run

4. К сожалению, у меня это решение тоже не сработало — я уже попробовал его в паре проектов

5. Этот подход является своего рода обходным путем. Я предполагаю, что реальная проблема заключается в том, что у вас есть код, запущенный в Spork.prefork, который загружает модели. У меня была похожая проблема, и я смог отладить ее, вызвав spork --diagnose . В нем будут перечислены все файлы, загруженные Spork, и обратная трассировка того, что загрузило каждый файл. В моем случае у меня был инициализатор, ссылающийся на контроллер, вызывающий проблемы с тем, что этот контроллер не перезагружался при каждом тестовом запуске.

Ответ №2:

Попробуйте ActionDispatch::Reloader

В дополнение к config.cache_classes = false настройке в config/environments/test.rb , кажется, что следующее позволяет DataMapper и Spork хорошо работать для нашей команды:

 Spork.each_run do

  # Routes
  MyApp::Application.reload_routes!

  if Spork.using_spork?
    # Reload all app files
    ActionDispatch::Reloader.cleanup!
    ActionDispatch::Reloader.prepare!

    # All factories
    FactoryGirl.reload
  end

end
  

Комментарии:

1. Неплохо. Я этого не ожидал, но это, похоже, решило мои проблемы с Mongoid и Spork. Вся остальная документация по этому вопросу ( Spork.trap_method Jujitsu и ActiveSupport::Dependencies.clear ) вообще не работала. Я даже смог избавиться от своей дополнительной ловушки на Rails::Mongoid.load_models .

2. Этот подход фактически включает ActiveSupport::Dependencies.clear и многое другое. Вызываю ActionDispatch::Reloader.cleanup! и приготовьтесь! это именно то, что перезагружает! происходит в консоли rails. 1

Ответ №3:

Привет, я хотел поделиться тем, что помогло мне снова запустить тест.
Оказывается, мне пришлось добавить shared_connection трюк, поскольку spork жаловался на потерю соединения.
После этого мне пришлось сдвинуть dependency.clear строку в конце блока, поскольку она кэшировала мои модели.

 Spork.each_run do
  # ActiveSupport::Dependencies.clear # <-- moved this line at end of block as suggested by @solnic
  ActiveRecord::Base.instantiate_observers
  MyApp::Application.reload_routes!
  FactoryGirl.reload

  class ActiveRecord::Base
    mattr_accessor :shared_connection
    @@shared_connection = nil

    def self.connection
      @@shared_connection || retrieve_connection
    end
  end
  ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

  ActiveSupport::Dependencies.clear # <-- line moved here

end if Spork.using_spork?