NameError: неинициализированная константа при попытке выполнить тесты рельсов

В приложении Rails 3.2.13, которое я сейчас пишу, у меня есть модель с именем Business. Поскольку эта модель становилась все толще и толще, я решил разделить ее на две части, извлекая весь код, связанный с доступностью, в задачу Rails с именем Availability, хранящуюся по адресу models/concerns/business.

class Business
  module Availability
    extend ActiveSupport::Concern

    AVAILABILITY_OPEN        =  1
    AVAILABILITY_CLOSED      = -1
    AVAILABILITY_COMPLETE    = -2

...

Так как проблемы не включены в Rails по умолчанию, я поместил следующую строку в config/application.rb для их автоматической загрузки:

config.autoload_paths += %W(#{config.root}/app/models/concerns)

Проблема в том, что после разделения все мои тесты перестали работать, возвращая ошибку NameError: uninitialized constant Availability. Я предполагаю, что мне нужно как-то потребовать эту заботу в своих тестах, но я пока не успел это сделать, и я также не понимаю, зачем эта забота нужна даже в тестах, которые ее не используют.

Ниже приведена трассировка стека, возвращенная после выполнения тестов:

NameError: uninitialized constant Availability
    (erb):9:in `<main>'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/erb.rb:849:in `eval'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/erb.rb:849:in `result'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures/file.rb:51:in `render'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures/file.rb:43:in `rows'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures/file.rb:29:in `each'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:670:in `block (2 levels) in read_fixture_files'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures/file.rb:20:in `open'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:669:in `block in read_fixture_files'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:668:in `each'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:668:in `read_fixture_files'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:548:in `initialize'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:482:in `new'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:482:in `block (2 levels) in create_fixtures'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:479:in `map'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:479:in `block in create_fixtures'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:232:in `disable_referential_integrity'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:476:in `create_fixtures'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:895:in `load_fixtures'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:849:in `setup_fixtures'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:407:in `_run__871072887135343583__setup__3260066542044458782__callbacks'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:405:in `__run_callback'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:385:in `_run_setup_callbacks'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:81:in `run_callbacks'
    /home/sergio/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/testing/setup_and_teardown.rb:35:in `run'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:919:in `block in _run_suite'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:912:in `map'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:912:in `_run_suite'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:657:in `block in _run_suites'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:655:in `each'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:655:in `_run_suites'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:867:in `_run_anything'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:1060:in `run_tests'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:1047:in `block in _run'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:1046:in `each'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:1046:in `_run'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/minitest/unit.rb:1035:in `run'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:21:in `run'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:774:in `run'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:366:in `block (2 levels) in autorun'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:27:in `run_once'
    /home/sergio/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/test/unit.rb:365:in `block in autorun'

ОБНОВЛЕНИЕ

Это отрывок из класса Business, в который входит проблема Availability:

class Business < ActiveRecord::Base
  include Availability
  include EmailVirtualAttribute
  include TelephoneVirtualAttribute

  belongs_to :place
  has_many :businesses_users
  has_many :users,        :through => :businesses_users, :uniq => true
  has_many :customers,    :inverse_of => :business, :dependent => :destroy
  has_many :emails,       :as => :contactable, :class_name => 'Email'
  has_many :telephones,   :as => :contactable, :class_name => 'Telephone'

  ...

Конфигурации разработки/тестирования стандартные, никаких изменений не вносилось.

test.rb

Rendezvous::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # The test environment is used exclusively to run your application's
  # test suite. You never need to work with it otherwise. Remember that
  # your test database is "scratch space" for the test suite and is wiped
  # and recreated between test runs. Don't rely on the data there!
  config.cache_classes = true

  # Configure static asset server for tests with Cache-Control for performance
  config.serve_static_assets = true
  config.static_cache_control = "public, max-age=3600"

  # Log error messages when you accidentally call methods on nil
  config.whiny_nils = true

  # Show full error reports and disable caching
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false

  # Raise exceptions instead of rendering exception templates
  config.action_dispatch.show_exceptions = false

  # Disable request forgery protection in test environment
  config.action_controller.allow_forgery_protection    = false

  # Tell Action Mailer not to deliver emails to the real world.
  # The :test delivery method accumulates sent emails in the
  # ActionMailer::Base.deliveries array.
  config.action_mailer.delivery_method = :test

  # Raise exception on mass assignment protection for Active Record models
  config.active_record.mass_assignment_sanitizer = :strict

  # Print deprecation notices to the stderr
  config.active_support.deprecation = :stderr
end

development.rb

Rendezvous::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes = false

  # Log error messages when you accidentally call methods on nil.
  config.whiny_nils = true

  # Show full error reports and disable caching
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false

  # Don't care if the mailer can't send
  config.action_mailer.raise_delivery_errors = false

  # Print deprecation notices to the Rails logger
  config.active_support.deprecation = :log

  # Only use best-standards-support built into browsers
  config.action_dispatch.best_standards_support = :builtin

  # Raise exception on mass assignment protection for Active Record models
  config.active_record.mass_assignment_sanitizer = :strict

  # Log the query plan for queries taking more than this (works
  # with SQLite, MySQL, and PostgreSQL)
  config.active_record.auto_explain_threshold_in_seconds = 0.5

  # Do not compress assets
  config.assets.compress = false

  # Expands the lines which load the assets
  config.assets.debug = true
end

ОБНОВЛЕНИЕ 2

Похоже, ошибки, возникающие при выполнении тестов, вызваны фикстурами. Если я прокомментирую загрузку fixtures :all для test_helper.rb и создам простой тест, который просто подтверждает истинность, этот тест пройдет, но не при загрузке приборов.


person Sergio    schedule 10.07.2013    source источник


Ответы (3)


Наконец-то я нашел причину, по которой все мои тесты завершались с ошибкой. Я ссылался на константу, объявленную в концепте Availability, используя Availabiliy:: вместо использования Business::. Кроме того, мои тесты не были синхронизированы с текущим кодом, что делало поиск ошибки намного сложнее, чем следовало бы. Замена всех ссылок на Availability на Business решила проблему. Урок здесь таков: всегда синхронизируйте приложение и тестируемый код.

Спасибо Лихтамбергу за всю его поддержку.

person Sergio    schedule 20.07.2013

Попробуйте это с конкретным названием модели. Например, User :: Confirmation

# -*- encoding : utf-8 -*-
require 'active_support/concern'

module Business::Availability
  extend ActiveSupport::Concern

И это:

config.autoload_paths += Rails.root.join("app", "models", "concerns")
person BvuRVKyUVlViVIc7    schedule 10.07.2013
comment
Спасибо за ваш ответ, Лихтамберг, к сожалению, он продолжает возвращать ту же ошибку. Любые идеи? - person Sergio; 11.07.2013
comment
Лихтамберг, я обновил вопрос соответствующей частью класса business. Скажи мне, если тебе нужно что-то еще. - person Sergio; 13.07.2013
comment
Я думаю, вы имели в виду config.autoload_paths += Dir[Rails.root.join("app", "models", "concerns")]. В любом случае, это тоже не работает, возвращает ту же ошибку. Обратите внимание, что мой текущий код работает в приложении, только при тестировании появляется эта ошибка. - person Sergio; 13.07.2013
comment
ах, хорошо, да, пожалуйста, опубликуйте свои конфиги разработки/тестирования - person BvuRVKyUVlViVIc7; 13.07.2013
comment
Я обновил вопрос данными, которые вы просили. Благодарю вас! - person Sergio; 13.07.2013
comment
Это происходит со всеми тестами или только с конкретным? - person BvuRVKyUVlViVIc7; 14.07.2013
comment
это происходит со всеми тестами - person Sergio; 14.07.2013

Я как бы изолировал источник проблемы, которым являются светильники. Я использовал метод fixtures :all в test_helper.rb. Изменив его, чтобы просто запустить прибор customers.yml, я могу запустить customer_test.rb без ошибок. Чего я пока не знаю, какие приборы вызывают проблемы (я полагаю, что businesses.yml и, возможно, родственные, но я не проверял) и почему вызывают проблему.

person Sergio    schedule 17.07.2013