Jay Fields posts about one expectation per spec, something that I generally agree with but often find hard to practice. I typically find myself with one mock and one assert per test, such as this example from the rush specs:
it "transmits file_contents" do
@con.should_receive(:transmit).with(:action => 'file_contents', :full_path => 'file').and_return('contents')
@con.file_contents('file').should == 'contents'
end
I want to test both the input and the output - that the file_contents method calls the right method with the right arguments, and that it returns the expected value. Breaking this into two specs would be:
it "transmits file_contents" do
@con.should_receive(:transmit).with(:action => 'file_contents', :full_path => 'file')
@con.file_contents('file')
end
it "gets the right return value from file_contents" do
@con.stub!(:transmit).and_return('contents')
@con.file_contents('').should == 'contents'
end
This is a lot more verbose but I don’t feel it adds a whole lot of clarity. Checking both the input and the output in one place seems reasonable to me. But I’ll keep this in the back of my head and see how it influences my spec-writing.
Another item I spotted in Jay’s example specs is stub_everything. I wasn’t previously aware of this. (His examples use Mocha, but the RSpec mocks have the same exact method.) Like this:
class BankAccount
def transfer(other_account, amount)
balance -= amount
other_account.balance += amount
end
end
it "transfers money out of this account"
@account.balance = 10
@account.transfer(stub_everything, 1)
@account.balance.should == 9
end
stub_everything returns an object that responds to every possible method, but does nothing on the calls. This allows you to effectively ignore any operations on that object, rather than having to stub every call explcitly.