On Nov 23, 2011, at 3:33 PM, Patrick J. Collins wrote:

> I wrote a test that looked like this:
> 
>       it "increases the user's reputation" do
>               lambda { @comment.update_attribute(:helpful, true) }.should 
> change(@seller.reload, 
> :reputation_score).by(Event.reputation_change_for(:mark_helpful))

The change matcher has several forms, including:

  lambda { ... }.should change(object, method).by(amount)
  lambda { ... }.should change { object.method }.by(amount)

Your example uses the former, which results in the following (roughly):

  receiver = @seller.reload
  value_before = receiver.reputation_score
  { @comment.update_attribute(:helpful, true) }.call
  value_after = receiver.reputation_score
  (value_after - value_before).should 
eq(Event.reputation_change_for(:mark_helpful))

As you can see, @seller.reload is only evaluated once, and its reputation score 
is going to be the same both times. If you want @seller.reload eval'd before 
and after, then you have to use the block form:

  lambda { @comment.update_attribute(:helpful, true) }.
    should change {@seller.reload.reputation_score }.
    by(Event.reputation_change_for(:mark_helpful))

Tangent: this is testing two things - @seller.reputation_score and 
Event.reputation_change_for(:mark_helpful). If either is failing to work 
correctly, this example won't tell you which. I'd recommend sticking to 
literals in expectations:

  lambda { @comment.update_attribute(:helpful, true) }.
    should change {@seller.reload.reputation_score }.by(3)

HTH,
David

>       end
> 
> And I am getting this error:
>  1) Comment comments on posts marking a comment as helpful increases the 
> user's reputation
>     Failure/Error: lambda { @comment.update_attribute(:helpful, true) 
> }.should change(@seller.reload, 
> :reputation_score).by(Event.reputation_change_for(:mark_helpful))
>       reputation_score should have been changed by 3, but was changed by 0
> 
> --
> 
> The way the actual code works is, I have a comment observer that does:
> 
>       def after_update(comment)
>               Event.create_for_user(comment.user, :mark_helpful)
>       end
> 
> And event.rb does something like:
> 
>       def create_for_user(user, event_type)
>               create!(:user => user, :reputation_change => 
> Event::SCORES[event_type])
>       end
> 
> The user model has an before_save callback which does:
> 
>       def sum_points
>               self.reputation_score = events.sum(:reputation_change)
>               self.points = events.sum(:points_change)
>       end
> 
> 
> ---
> 
> Anyway, so this test fails, and I am not sure why...  If I write it in a
> slightly less-cool way:
> 
>       it "increases the user's reputation" do
>               @seller.reputation_score.should == 0
>               @comment.update_attribute(:helpful, true)
>               @seller.reload.reputation_score.should == 
> Event.reputation_change_for(:mark_helpful)
>       end
> 
> Then it passes...  If I throw in a debugger statement in there and manually
> call the code, the reputation_score does indeed increase......  So I am
> confused why the lambda {}.change thing isn't working?
> 
> Thanks.
> 
> Patrick J. Collins
> http://collinatorstudios.com

_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to