RSpec: testing models using methods that call update_attributes

RSpec is new here.

I am trying to test my models that have methods that use update_attributes to update the values ​​of other models.

I am sure that the values ​​are stored in the database, but they do not pass the specification.

However, when I include something like @user.reload , it works.

I wonder if I'm not mistaken. In particular, how should you test models that change the attributes of other models?

UPDATED with code:

 describe Practice do before(:each) do @user = build(:user) @user.stub!(:after_create) @user.save! company = create(:acme) course = build(:acme_company, :company => company) course.save! @practice = create(:practice, :user_id => @user.id, :topic => "Factors and Multiples" ) end describe "#marking_completed" do it "should calculate the points once the hard practice is done" do @practice.question_id = Question.find(:first, conditions: { diff: "2" }).id.to_s @practice.responses << Response.create!(:question_id => @practice.question_id, :marked_results => [true,true,true,true]) @practice.save! lambda { @practice.marking_completed @practice.reload # <-- Must add this, otherwise the code doesn't work }.should change { @practice.user.points }.by(20) end end 

end

In Practice.rb

 def marking_completed # Update user points user.add_points(100) self.completed = true self.save! 

end

In User.rb

 def add_points(points) self.points += points update_attributes(:points => self.points) 

end

+4
source share
1 answer

What happens is that the user object is cached in the @practice variable, so a reboot is required when the user has been updated. You cannot do this with the current specification, but you might think about what you are actually testing. It seems strange to me that your specification is for the Practice model, but the statement should change { @practice.user.points }.by(20) really describes the behavior of the User.

I would personally dismember the Practice and User models a bit more in your specification and independently check their behavior.

 describe "#marking_completed" do before do @practice.question_id = Question.find(:first, conditions: { diff: "2" }).id.to_s @practice.responses.create!(:question_id => @practice.question_id, :marked_results => [true,true,true,true]) @practice.save! end it "should calculate the points once the hard practice is done" do @practice.user.should_receive(:add_points).with(20).once @practice.marking_completed end end 

Then I would add a separate test for the User model:

 describe User do it 'should add specified points to a user' do lambda { subject.add_points(100) }.should change { subject.points }.by(100) end end 

Another kind of side note is that it is not clear what Question.find returns, or why user points change to 20 in your test.

+5
source

Source: https://habr.com/ru/post/1392227/


All Articles