Improve your RSpec with simple custom matchers
RSpec is great:
it "should be its own root" do @node.root.should == @node end it "should add a child" do @node.children.size.should == 0 child = @klass.new @node.add_child(child) @node.children.size.should == 1 child.parent.should == @node child.root.should == @node end
Looks beautiful. However, look at line #2. What would the output be if that test fails? The message would be something like this: "expected #{@target.inspect} to the same as #{@expected.inspect}".
Inspecting an object like a tree node could result in multiple pages worth of data and the output basically becomes unreadable if there’s an array of objects.
This problem could easily be fixed with a custom expectation matcher.
module BeTheSameAsMatcher
class BeTheSameAs
def initialize(expected)
@expected = expected
end
def matches?(target)
@target = target
@target.eql?(@expected)
end
def failure_message
"expected <#{to_string(@target)}> to " +
"the same as <#{to_string(@expected)}>"
end
def negative_failure_message
"expected <#{to_string(@target)}> not to " +
"be the same as <#{to_string(@expected)}>"
end
# Returns string representation of an object.
def to_string(value)
# indicate a nil
if value.nil?
'nil'
end
# join arrays
if value.class == Array
return value.join(", ")
end
# otherwise return to_s() instead of inspect()
return value.to_s
end
end
# Actual matcher that is exposed.
def be_the_same_as(expected)
BeTheSameAs.new(expected)
end
end
As you can see, methods failure_message and negative_failure_message define our error messages. Instead of default inspect call, I’m using a custom to_string method which will either return a join for an Array or to_s for any other object.
To make this available in all of your specs, the module needs to be added in your `spec_helper.rb` like so:
require 'spec/be_the_same_as' Spec::Runner.configure do |config| config.include(BeTheSameAsMatcher) end
After this, we can change our line #2 from the original script to this:
it "should be its own root" do @node.root.should be_the_same_as(@node) end
No comments yet, be the first one!
Leave a Reply