2012-03-12 127 views
1

在我的模型,我動態地創建一些方法基於數​​據庫記錄:測試動態創建的方法

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 &後衛,並使用數據庫清理程序和截斷策略(根據Railscast #257,因爲我使用的是Selenium),所以可能會使事情複雜化。

回答

0

我想出的解決方案是將創建的運行時方法抽象爲一個庫文件,然後在我的測試文件中,在每次測試之前刪除並重新聲明我的類,然後將實際的類(和藍圖)重新加載到該套件的結尾:

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 

這樣,我創建了一個基本類爲每個測試,添加運行方式爲必然,並返回到實際上課的時候,我做了。

0

試用enumerize寶石。這使您的狀態字段像枚舉器一樣,並構建「#{status.name.downcase}?」爲您的模型。 This gem附帶它自己的rspec-matchers,使您的單元測試更容易。