While working my way through The RSpec Book, I came across the as_null_object method. I don’t understand the explanation the book provides as to why it’s needed:
… the simplest way is to tell the double output to only listen for the messages we tell it to expect and ignore any other messages.
But why does the example code fail? When we call double('output') in each example, are we not creating a new double object for each example and sending it a single message?
What I would like is an deeper explanation (than the book) of why the example code fails, and how as_null_object addresses the issue.
it "sends a welcome message" do
output = double('output')
game = Game.new(output)
output.should_receive(:puts).with('Welcome to Codebreaker!')
game.start
end
it "prompts for the first guess" do
output = double('output')
game = Game.new(output)
output.should_receive(:puts).with('Enter guess:')
game.start
end
The book tries to explain the reason for the error in an earlier section, but again I don’t understand the explanation.
We’ve told the double in the first example to expect
puts"Welcome to Codebreaker!" and we’ve satisfied that requirement, but we’ve only told it to expect "Welcome to Codebreaker!" It doesn’t know anything about "Enter guess:"Similarly, the double in the second example expects "Enter guess:" but the first message it gets is "Welcome to Codebreaker".
When you create a double with
output = double('output')and then pass it to the new game inGame.new(output), that double will receive every message that it is passed in the codebreaker game code. You haven’t included it, but thestartmethod has the following code:Here, remember that the double
outputhas been assigned to the instance variable@outputin thegame‘sinitializemethod, so in each spec it is called with two messages, first with ‘Welcome to Codebreaker!’, then with ‘Enter guess:’.Without
as_null_object, theoutputdouble will fail when it receives anything other than what it expects, i.e. in the first spec anything other than ‘Welcome to Codebreaker!’ and in the second spec anything other than ‘Enter guess:’. By usingas_null_objecton the double, you tell it to sit and wait and ignore anything other than what it expects. This avoids the problem above.Hope that helps.