Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing a before_save callback with Rspec and Factory Girl

I am pretty sure I am missing something really basic here.

I want to test if a before_save callback does what it is supposed to do, not just that it is called.

I wrote the following test:

it 'should add lecture to question_type' do      
  @course = Factory :course,
                    :start_time => Time.now - 1.hour,
                    :end_time => Time.now                        
  @question = Factory.create(:question, 
                             :course_id => @course.id, 
                             :created_at => Time.now - 10.minutes)                          
  @question.question_type.should == 'lecture'      
end

And I have the following factories for course and question:

Factory.define :course do |c|
  c.dept_code {"HIST"}
  c.course_code { Factory.next(:course_code) }
  c.start_time { Time.now - 1.hour }
  c.end_time { Time.now }
  c.lecture_days { ["Monday", Time.now.strftime('%A'), "Friday"]  }
end

Factory.define :question do |q|
  q.content {"Why don't I understand this class!?"}
  q.association :course
end

And I wrote the following callback in my Question model:

before_save :add_type_to_question

protected

def add_type_to_question
  @course = Course.find(self.course_id)
  now     = Time.now
  if (time_now > lecture_start_time && time_now < lecture_end_time ) && @course.lecture_days.map{|d| d.to_i}.include?(Time.now.wday)
    self.question_type = "lecture"
  end    
end

The test keeps failing saying that "got: nil" for question_type instead of 'lecture'

Since I didn't see anything obviously wrong with my implementation code, I tried the callback in my development environment and it actually worked adding 'lecture' to question_type.

This makes me think that there might be something wrong with my test. What am I missing here? Does Factory.create skip callbacks by default?

like image 386
Philip V Avatar asked Jan 31 '12 23:01

Philip V


1 Answers

I would not use Factory.create to trigger the process. FactoryGirl should be used to create the test setup, not to trigger the actual code you want to test. Your test would then look like:

it 'should add lecture to question_type' do      
  course = Factory(:course, :start_time => Time.now - 1.hour, :end_time => Time.now)
  question = Factory.build(:question, :course_id => course.id, :created_at => Time.now - 10.minutes, :question_type => nil)

  question.save!                          
  question.reload.question_type.should == 'lecture'      
end

If this test still fails, you can start debugging:

Add a puts statement inside add_type_to_question and another one inside the if statement and see what happens.

like image 194
Yves Senn Avatar answered Sep 24 '22 21:09

Yves Senn