I have been using rspec for for 8 months and I really wanted something like assert_difference in my specs.
Seeing as its really easy to write custom matchers in rspec, I whipped one up really quick that lets me do this:
lambda { User.count }.should be_different_by(1) { User.create }
Which turns out to be the same thing as:
orig_count = User.count
User.create
User.count.should ==(orig_count + 1)
Which at first glance you may think is not even worth it, but when you have 50+ create actions and in your controller specs your doing at least 1 check for the count to go up (or stay the same) then you can start to see the real benefits of be_different_by. I count 110 uses of be_different_by in my current project. Thats 220 saved lines of code, and, I think, 110 specs that expose their purpose more clearly.
Here is the code for be_different_by:
module Spec
module Matchers
class BeDifferentBy
attr_reader :difference, :lamb, :target, :initial, :after
def initialize(difference, b)
@difference, @lamb = difference, b
end
def matches?(target)
@target = target
@initial = target.call
@lamb.call
@after = target.call
(@initial + @difference) == @after
end
def failure_message
"expected initial value of <#{@initial}> to be <#{(@initial + @difference)}> but was <#{@after}>"
end
def negative_failure_message
"expected initial value of <#{@initial}> NOT to be <#{(@initial + @difference)}> but was <#{@after}>"
end
end
def be_different_by(difference, &b)
BeDifferentBy.new(difference, b)
end
end
end
And here is the be_different_by spec (yes I am spec'ing a custom matcher, sue me):
describe "BeDifferentBy should match correctly" do
it "should work for shoulds" do
@init = 0
lambda { @init }.should be_different_by(1) { @init += 1 }
end
it "should work for should_nots" do
@init = 0
lambda { @init }.should_not be_different_by(2) { @init += 1 }
end
end
For more info on creating custom matchers check out Jordan McKible's tutorial.
December 11th, 2007 at 08:58 AM RSpec has the "change" matcher that can do this too: http://rspec.rubyforge.org/rdoc/classes/Spec/Matchers.html#M000256