Stubbing a return value in RSpec - correct usage of doubles and stubs
<p>I have run into confusion tying together a test double and stubbing it. My question is -  what is the most appropriate way to test the <code>confirm_purchase_order</code> and <code>create_order</code> methods in <code>class PurchaseOrder</code>?</p>

<p>I have included the relevant code following code: </p>

<pre><code>class PurchaseOrder
  attr_reader :customer, :products

  def initialize(customer)
    @products = {}
    @customer = customer
  end

  ....some other methods

  def add_product(product, quantity = 1)
    @products[product] = (@products[product] ? @products[product] + quantity :  quantity )
    puts "You haved added #{quantity} #{product.title}'s to your purchase order"
  end

  def confirm_purchase_order
    purchase_order_total
    raise "Your PO appears to be empty! Add some products and try again." unless self.total.to_f.round(2) &gt; 0

    create_order
    create_invoice

    return "We have generated an Invoice and created an order."
  end

  def create_order
    order = Order.new(customer)
    order.products = @products.clone
  end

  def create_invoice
    invoice = Invoice.new(customer)
    invoice.products = @products.clone
  end
end
</code></pre>

<hr>

<pre><code>class Order
  attr_reader :customer
  attr_accessor :status, :total, :products

  def initialize(customer)
    @products = {}
    @status = :pending
    @customer = customer
  end
</code></pre>

<hr>

<pre><code>class Customer
  attr_reader :name, :type

  def initialize(name, type)
    @name = name.to_s
    @type = type.to_sym
  end
</code></pre>

<hr>

<pre><code>class Invoice

  attr_reader :customer, :products
  attr_accessor :total

  def initialize(customer, products)
    @products = {}
    @customer = customer
    @payment_recieved = false
  end
end
</code></pre>

<hr>

<p>I want to test the <code>confirm_purchase_order</code> method as well as the <code>create_order</code> method in <code>class PurchaseOrder</code>. My approach so far:</p>

<p>I need some object doubles and an actual <code>PurchaseOrder object</code></p>

<pre><code>describe PurchaseOrder do
  let(:product) { double :product, title: "guitar", price: 5 }
  let(:order) { instance_double(Order) }
  let(:customer) { double :customer, name: "Bob", type: :company }
  let(:products) { {:product =&gt; 1} }

  let(:purchase_order) { PurchaseOrder.new(customer) }

  describe "#create_order" do

    it "returns an order" do
      expect(Order).to receive(:new).with(customer).and_return(order)
      allow(order).to receive(products).and_return(???products??!)

      purchase_order.add_product(product, 1)
      purchase_order.create_order
      expect(order.products).to eq (products)
    end
  end
end
</code></pre>

<p>I have also looked at the use of:</p>

<pre><code> # order.stub(:products).and_return(products_hash)
 # allow_any_instance_of(Order).to receive(:products) { products_hash }
 # order.should_receive(:products).and_return(products_hash)
</code></pre>

<p>To setup the order double to return a products hash when <code>order.products</code> is called, but these all feel like they are 'rigging' the test too much. What is the most appropriate way to test the <code>confirm_purchase_order</code> and <code>create_order</code> methods in <code>class PurchaseOrder</code>?</p>