Тестирование динамически создаваемых методов - PullRequest
1 голос
/ 13 марта 2012

В моей модели я динамически создаю несколько методов на основе записей базы данных:

class Job < ActiveRecord::Base
  belongs_to :job_status

  # Adds #requisition?, #open?, #paused?, #closed?
  class_eval do    
    JobStatus.all.each do |status|
      unless method_defined? "#{status.name.downcase}?"
        define_method("#{status.name.downcase}?") do 
          job_status_id == status.id
        end
      end
    end
  end
end

class JobStatus < ActiveRecord::Base
  has_many :jobs
end

Таблица job_statuses содержит некоторые начальные данные, поэтому не будет часто меняться, но в случаеМне нужно добавить новые статусы, мне не нужно добавлять больше кода, чтобы получить логический метод для нового статуса.

Однако я не уверен, как тестировать эти методы, потому что когда rspec запускает job_statuses таблица, очевидно, пуста, и когда создаются JobStatus объекты, Job инициализируется, но поскольку никаких объектов еще не существует, он не создает никаких методов, и мои тесты не выполняются, потому что методы не существуют.

Обратите внимание, что я использую rspec с spork & guard и использую очиститель базы данных со стратегией усечения (согласно Railscast # 257 , так как я использую Selenium), так что это, вероятно, усложняетвопросы.

Ответы [ 2 ]

0 голосов
/ 19 июня 2013

Попробуйте с перечислить драгоценный камень. Это сделает ваше поле статуса похожим на перечислитель и создаст "# {status.name.downcase}?" для ваших моделей. Этот драгоценный камень поставляется с собственными rspec-matchers, облегчающими ваш юнит-тест.

0 голосов
/ 29 марта 2012

Решение, которое я придумал, состояло в том, чтобы абстрагировать создание методов времени выполнения в файл библиотеки, а затем в моем тестовом файле удалять и повторно объявлять мой класс перед каждым тестом и перезагружать реальный класс (и чертежи) в конец сюиты:

describe AssociationPredicate do
  before(:all) do
    ["Continuous", "Standard"].each { |type| JobType.create!(:job_type => type) }
    ["Requisition", "Open", "Paused", "Closed"].each { |status| JobStatus.create!(:job_status => status) }
  end

  after(:all) do
    DatabaseCleaner.clean_with :truncation, :only => %w( job_types job_statuses )

    # Reload Job model to remove changes
    Object.send(:remove_const, 'Job')
    load 'job.rb'
    load 'support/blueprints.rb'
  end

  before(:each) do
    Object.send(:remove_const, 'Job')

    # Redefine Job model for testing purposes
    class Job < ActiveRecord::Base
      belongs_to  :job_type
      belongs_to  :job_status

      has_many    :job_applications
    end
  end

  it "should add methods when included" do
    Job.send(:association_predicate, :job_type)
    job.should respond_to(:continuous?)
    job.should respond_to(:standard?)
  end
end

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...