In my model, I dynamically create some methods based on database records:
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
The job_statuses
table contains some seed data, so is not going to be frequently changing, but in case I ever need to add new statuses, I don't have to add more code to get a boolean method for the new status.
However, I am not sure how to test these methods, because when rspec starts the job_statuses
table is obviously empty, and when the JobStatus
objects are created, Job
gets initialized, but since no objects exist yet, it doesn't create any methods, and my tests fail because the methods don't exist.
Note that I am using rspec with spork & guard, and using database-cleaner with the truncation strategy (as per Railscast #257 , since I'm using Selenium), so that probably complicates matters.
The solution I came up with was to abstract the creation of runtime methods out into a library file, and then in my test file, remove and redeclare my class before each test, and reload the actual class (and blueprints) at the end of the suite:
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
This way, I create a basic class for each test, add the runtime methods as necessarily, and return to the actual class when I'm done.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.