0
votes

I'm trying to follow the RSpec book right now, but it doesn't seem very clear to me. It has a lib/codebreaker/game.rb file:

module Codebreaker
  class Game
    def initialize(output)
      @output = output
    end
    def start
      @output.puts "Welcome to Codebreaker!" 
    end
  end
end        

I have a spec/codebreaker/game_spec.rb file:

require 'spec_helper'

module Codebreaker
  describe Game do
    describe "#start" do
      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"
    end
  end
end

So currently, the "it 'sends a welcome message'" test passes, but I don't understand why.

The game_spec file says that "output" should receive a puts command with "Welcome to Codebreaker!". However, in the game.rb file, we clearly see that output is an ARGUMENT to the intialize method. @outputs, the instance variable and NOT the argument parameter, has puts "Welcome to Codebreaker!" called to it. Why should this test pass when clearly output is not receiving :puts, but @output is?

I would understand if @output.should_receive(:puts).with("Welcome to Codebreaker!") passed, but output is just a parameter passed to initialize. How does RSpec know that output is actually @output or even have access to @output?

1

1 Answers

3
votes

However, in the game.rb file, we clearly see that output is an ARGUMENT to the intialize method.

Yes, this allows your test to pass in an output object designed for testing. It gets saved with this code here:

def initialize(output)
  @output = output
end

So then,

@outputs, the instance variable and NOT the argument parameter, has puts "Welcome to Codebreaker!" called to it.

It's the same object because initialize sets whatever was passed in as an argument to the instance variable @output. This instance variable is now available in every instance method.

Why should this test pass when clearly output is not receiving :puts, but @output is?

Because it's the same object. The test passes the object in, it gets saved to @output and then eventually puts is called on it.