When spec-ing something that calls method which takes a set of nested hashes (as many Rails methods do), it may be tempting to use #hash_including to test for only the values you care about. However #hash_including won’t work the way we might hope for nested hashes. Take the following (highly contrived) example:
describe CoffeeMaker do before :each do @it = CoffeeMaker.new end it "should receive #make_coffee with roast => medium" do @it.should_receive(:make_coffee). with(:water => :filtered, :beans => hash_including(:roast => :medium)) @it.make_coffee(:water => :filtered, :beans => { :origin => "Guatemala", :roast => :medium }) end end
If we run this we get a failure:
1)
Spec::Mocks::MockExpectationError in 'CoffeeMaker should receive #make_coffee with roast => medium'
Mock 'CoffeeMaker' expected :make_coffee with ({:water=>:filtered, :beans=>#<Spec::Mocks::ArgumentConstraints::HashIncludingConstraint:0x120b6c8 @expected={:roast=>:dark}>}) but received it with ({:water=>:filtered, :beans=>{:roast=>:medium, :origin=>"Guatemala"}})
Clearly #hash_including was only intended to work with shallow hashes.
Instead, we can use a lesser-known feature of RSpec’s mock objects to test only the values we care about:
describe CoffeeMaker do before :each do @it = CoffeeMaker.new end it "should receive #make_coffee with roast => medium" do @it.should_receive(:make_coffee) do |options| options[:beans][:roast].should == :medium end @it.make_coffee(:water => :filtered, :beans => { :origin => "Guatemala", :roast => :medium }) end end
Here we’ve supplied a block to #should_receive. The block will be called when the mocked method is called, and will be passed whatever arguments the mocked method was called with. Inside we can use any kind of RSpec assertions we like.
Here’s the failure message if we supply :roast => :dark instead of :medium:
Spec::Mocks::MockExpectationError in 'CoffeeMaker should receive #make_coffee with roast => medium'
Mock 'CoffeeMaker' received :make_coffee but passed block failed with: expected: :medium,
got: :dark (using ==)
Add New Comment
Thanks. Your comment is awaiting approval by a moderator.
Do you already have an account? Log in and claim this comment.
Add New Comment