Отчеты SimpleCov не генерируются в приложении Rails 3 после запуска тестов RSpec с помощью Spork

Я только что установил гем SimpleCov для создания отчетов о покрытии кода в моем приложении Rails 3.2.6, и он отлично работает. с RSpec, только не со Spork. Я могу получить нужный правильный отчет, запустив rspec --no-drb spec/, но я также хотел бы получить их с помощью Spork, используя только rspec spec/.

Учитывая, что были люди, которые добились успеха с этим, вероятно, у меня есть ошибки в моей настройке. Я прочитал инструкции по установке, а также ошибка GitHub, которая якобы должна была исправить для пользователей Spork, но все равно не повезло. Мне интересно, есть ли кто-нибудь, кто может предоставить полный пример своего рабочего файла spec/spec_helper.rb, который я мог бы использовать для справки, поскольку обширный поиск в Google обнаружил только фрагменты. По совету других сайтов я попытался изменить config.cache_classes в config/environments/test.rb с true по умолчанию на false и !(ENV['DRB'] == 'true'), но безуспешно.

Для справки, вот как я настроен:

Gemfile

group :development, :test do
  # ...
  gem 'rspec-rails', '2.10.1'
end

group :test do
  # ...
  gem 'spork', '0.9.0'
  gem 'simplecov', '0.6.4', require: false
end

.spec

--colour
--drb

spec/spec_helper.rb (изменено в соответствии с ошибкой GitHub )

require 'simplecov'
SimpleCov.start 'rails'

require 'rubygems'
require 'spork'

Spork.prefork do
  unless ENV['DRB']
    require 'simplecov'
    SimpleCov.start 'rails'
  end

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

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

  RSpec.configure do |config|
    config.mock_with :rspec
    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.use_transactional_fixtures = true
    config.infer_base_class_for_anonymous_controllers = false
  end
end

Spork.each_run do
  if ENV['DRB']
    require 'simplecov'
    SimpleCov.start 'rails'
  end
end

Я пытался закомментировать/изменить два верхних оператора SimpleCov этого файла и операторы Simplecov внутри блоков Spork, но не могу найти подходящую комбинацию.

Что мне не хватает? Есть ли какие-либо другие файлы, которые мне нужно изменить?


person Paul Fioravanti    schedule 07.07.2012    source источник


Ответы (2)


Мне удалось получить работающую конфигурацию spec/spec_helper.rb, которая правильно выполняет SimpleCov, просто используя команду $ rspec spec/ благодаря комментарий к проблеме Github, который отправил меня на эту запись в блоге и его пример spec/spec_helper.rb. Все причины, почему это работает, содержатся в (очень подробной!) записи в блоге. Замените SampleApp именем вашего приложения.

spec/spec_helper.rb

require 'rubygems'
require 'spork'

Spork.prefork do
  unless ENV['DRB']
    require 'simplecov'
    SimpleCov.start 'rails'
  end

  require 'rails/application'
  require Rails.root.join("config/application")

  ENV["RAILS_ENV"] ||= 'test'
  require 'rspec/rails'
  require 'rspec/autorun'

  RSpec.configure do |config|
    config.mock_with :rspec
    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.use_transactional_fixtures = false

    config.before :each do
      if Capybara.current_driver == :rack_test
        DatabaseCleaner.strategy = :transaction
      else
        DatabaseCleaner.strategy = :truncation
      end
      DatabaseCleaner.start
    end

    config.after do
      DatabaseCleaner.clean
    end

    config.infer_base_class_for_anonymous_controllers = false
  end
end

Spork.each_run do
  if ENV['DRB']
    require 'simplecov'
    SimpleCov.start 'rails'
    SampleApp::Application.initialize!
    class SampleApp::Application
      def initialize!; end
    end
  end

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

Редактировать

Если вы используете Travis-CI, не используйте этот код как есть, потому что вы, скорее всего, получите undefined method 'root' for Rails:Module (NoMethodError) ошибка. Если вы знаете, как это исправить, поделитесь, пожалуйста.

Редактировать 2

Я заставил Travis CI работать, по сути, поместив все в блок Spork.each_run, что, похоже, значительно замедлило тесты. Должен быть лучший способ сделать это, или он просто не стоит того, чтобы не запускать $ rspec --no-drb spec/ один раз, чтобы получить отчет SimpleCov...

spec/spec_helper.rb

require 'rubygems'
require 'spork'

Spork.prefork do
  unless ENV['DRB']
    require 'simplecov'
    SimpleCov.start 'rails'
  end

  require 'rails/application'
  ENV["RAILS_ENV"] ||= 'test'
end

Spork.each_run do
  if ENV['DRB']
    require 'simplecov'
    SimpleCov.start 'rails'
    require Rails.root.join("config/application")
    SampleApp::Application.initialize!
    class SampleApp::Application
      def initialize!; end
    end
  end

  unless ENV['DRB']
    require File.expand_path("../../config/environment", __FILE__)
  end

  require 'rspec/rails'
  require 'rspec/autorun'

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

  RSpec.configure do |config|
    config.mock_with :rspec

    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.use_transactional_fixtures = false
    config.before :each do
      if Capybara.current_driver == :rack_test
        DatabaseCleaner.strategy = :transaction
      else
        DatabaseCleaner.strategy = :truncation
      end
      DatabaseCleaner.start
    end

    config.after do
      DatabaseCleaner.clean
    end
    config.infer_base_class_for_anonymous_controllers = false
  end
end

Редактировать 3

После использования этой конфигурации в течение нескольких дней, похоже, она не замедлила работу так сильно, как я думал ранее, поэтому я буду считать это принятым ответом, если не будет опубликован более элегантный ответ.

Редактировать 4

После использования этой конфигурации в течение нескольких месяцев я понял, что она работает медленнее, чем я думал. Частично это связано с осознанием того, что Spork может замедлять наборы тестов и лучше всего подходит для быстрого итеративного целенаправленного тестирования, а не для постоянного запуска с ним целых наборов тестов. Следующие вопросы SO и сообщения в блоге привели меня к приведенному ниже файлу spec_helper.rb, который может запускать SimpleCov со Spork или без него, работает быстрее, чем раньше, и работает с Capybara 2.0.

spec/spec_helper.rb

require 'rubygems'
require 'spork'
require 'simplecov'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'

Spork.prefork do
  ENV["RAILS_ENV"] ||= 'test'
  unless ENV['DRB']
    SimpleCov.start 'rails'
    require File.expand_path("../../config/environment", __FILE__)
  end

  require 'rspec/rails'
  require 'rspec/autorun'
  require 'capybara/rails'
  require 'capybara/rspec'

  # files to preload based on results of Kernel override code below
  # ie they took more than 100 ms to load
  require "sprockets"
  require "sprockets/eco_template"
  require "sprockets/base"
  require "active_record/connection_adapters/postgresql_adapter"
  require "tzinfo"
  require "tilt"
  require "journey"
  require "journey/router"
  require "haml/template"

  RSpec.configure do |config|
    config.mock_with :rspec

    # If you're not using ActiveRecord, or you'd prefer not to run each of your
    # examples within a transaction, remove the following line or assign false
    # instead of true.
    config.use_transactional_fixtures = false

    # If true, the base class of anonymous controllers will be inferred
    # automatically. This will be the default behavior in future versions of
    # rspec-rails.
    config.infer_base_class_for_anonymous_controllers = false

    config.include FactoryGirl::Syntax::Methods

    config.before :suite do
      # PerfTools::CpuProfiler.start("/tmp/rspec_profile")
      DatabaseCleaner.strategy = :transaction
      DatabaseCleaner.clean_with(:truncation)
    end

    # Request specs cannot use a transaction because Capybara runs in a
    # separate thread with a different database connection.
    config.before type: :request do
      DatabaseCleaner.strategy = :truncation
    end

    # Reset so other non-request specs don't have to deal with slow truncation.
    config.after type: :request  do
      DatabaseCleaner.strategy = :transaction
    end

    RESERVED_IVARS = %w(@loaded_fixtures)
    last_gc_run = Time.now

    config.before(:each) do
      GC.disable
    end

    config.before do
      DatabaseCleaner.start
    end

    config.after do
      DatabaseCleaner.clean
    end

    # Release instance variables and trigger garbage collection
    # manually every second to make tests faster
    # http://blog.carbonfive.com/2011/02/02/crank-your-specs/
    config.after(:each) do
      (instance_variables - RESERVED_IVARS).each do |ivar|
        instance_variable_set(ivar, nil)
      end
      if Time.now - last_gc_run > 1.0
        GC.enable
        GC.start
        last_gc_run = Time.now
      end
    end

    config.after :suite do
      # PerfTools::CpuProfiler.stop

      # REPL to query ObjectSpace
      # http://blog.carbonfive.com/2011/02/02/crank-your-specs/
      # while true
      #   '> '.display
      #   begin
      #     puts eval($stdin.gets)
      #   rescue Exception => e
      #     puts e.message
      #   end
      # end
    end
  end

  # Find files to put into preload
  # http://www.opinionatedprogrammer.com/2011/02/profiling-spork-for-faster-start-up-time/
  # module Kernel
  #   def require_with_trace(*args)
  #     start = Time.now.to_f
  #     @indent ||= 0
  #     @indent += 2
  #     require_without_trace(*args)
  #     @indent -= 2
  #     Kernel::puts "#{' '*@indent}#{((Time.now.to_f - start)*1000).to_i} #{args[0]}"
  #   end
  #   alias_method_chain :require, :trace
  # end
end

Spork.each_run do
  # This code will be run each time you run your specs.
  if ENV['DRB']
    SimpleCov.start 'rails'
    SampleApp::Application.initialize!
    class SampleApp::Application
      def initialize!; end
    end
  end

  # Requires supporting ruby files with custom matchers and macros, etc,
  # in spec/support/ and its subdirectories.
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
  FactoryGirl.reload
  I18n.backend.reload!
end
person Paul Fioravanti    schedule 31.08.2012

У меня это работает в приложении Rails с этими конкретными версиями:

  • rails (3.2.8)
  • guard (1.3.2)
  • guard-spork (1.1.0)
  • spork (0.9.2)
  • simplecov (0.6.4)
  • rspec-rails (2.11.0)

spec/spec_helper.rb выглядит так:

require "spork"

Spork.prefork do

end

Spork.each_run do
  require "simplecov"
  SimpleCov.start "rails"

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

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

  FactoryGirl.reload
end

Хотя требовать всего в блоке Spork.each_run с точки зрения производительности, вероятно, далеко не идеально, это правильно запускает SimpleCov при каждом вызове теста и, по-видимому, имеет относительно низкие накладные расходы.

Надеюсь, это поможет. Удачи!

person phlipper    schedule 31.08.2012
comment
Большое спасибо за ваш ответ. Я обновил свои рубиновые драгоценные камни, чтобы они соответствовали вашим, и протестировал ваш spec_helper.rb, но, к сожалению, у меня это не сработало; на самом деле это привело к тому, что некоторые из моих тестов провалились. Мой spec_helper.rb случайно не работает в вашем приложении? - person Paul Fioravanti; 31.08.2012
comment
Спасибо, что побудили меня взглянуть на это снова. Мне удалось решить мою проблему, используя код в моем ответе. Надеюсь, это сработает и для вас или, по крайней мере, даст какую-то ссылку. - person Paul Fioravanti; 01.09.2012
comment
Привет, Пол, это spec_helper.rb было извлечено из работающего приложения, хотя и не из того, которое использует Travis в данный момент. Я рад, что у вас все же получилось! - person phlipper; 03.09.2012