For instance, let's say I'm testing messages, and I want to verify that a given call properly delegates to a subordinate object of another type:
def test_read_by
@message.message_recipients.expects(:find_by_recipient_id).
with(@profile.id).
returns(MessageRecipient.new(:status_read => true))
assert @message.read_by?(@profile)
end
This is pretty straightforward, but seeing that other class name in there bothers me. I've had trouble with over-specific tests before. Here's a version using the stub method:
def test_read_by
@message.message_recipients.expects(:find_by_recipient_id).
with(@profile.id).
returns(stub(:is_read? => true))
assert @message.read_by?(@profile)
end
This is similar, but there are a couple of important differences. First, I no longer have to hardcode the class name of the subordinate object, which may change later. More importantly, I can mock the friendlier external interface of MessageRecipient without having to know anything else about the object or its contents. Other than that it's exactly the same as the previous test.
Now let's try it with mock:
def test_read_by
@message.message_recipients.expects(:find_by_recipient_id).
with(@profile.id).
returns(mock(:is_read? => true))
assert @message.read_by?(@profile)
end
Once again, very little difference. The call to stub is replaced by a call to mock with the same arguments. However if you run this test you'll see an extra assertion being checked. This is because mock will verify that every mocked method was called, as though you'd used expects. This means that in addition to the benefits conferred by using a stub object, you're now verifying that the object was used as intended.
0 comments:
Post a Comment