title: Rspec advice for testing service objects
body: <p>I'm writing Rspec tests for a service object that touches several models, but I feel like my test is too dependent on the internals of the method and therefore isn't very meaningful. Here's an example:</p>
  
  <pre><code>class MealServicer
  
    def self.serve_meal(meal, customer)
      meal.update_attributes(status: "served", customer_id: customer.id)
      order = customer.order
      OrderServicer.add_meal_to_order(meal, order)
      CRM.update_customer_record(customer) // external API call
    end
  
  end
  </code></pre>
  
  <p>I'd like to use doubles/stubs to mock the behavior without actually saving anything to the test database (for performance). But if I create doubles that respond to messages, then it feels like I'm testing one particular implementation of the serve_meal() method, and this test is too coupled to that particular implementation. For example, I need to make sure that my <code>customer</code> double responds to <code>order</code> and returns an <code>order</code> stub. Essentially, when everything is just a double and I have to explicitly state all dependencies by making sure doubles return other doubles, it feels like the tests end up being pretty meaningless. See here:</p>
  
  <pre><code>it "has a working serve_meal method" do
    meal = double(:meal)
    customer = double(:customer)
    order = double(:order)
  
    allow(customer).to_receive(:order).and_return(order)
    allow(OrderServicer).to_receive(:add_meal_to_order).and_return(true)
    allow(CRM).to_receive(:update_customer_record).and_return(true)
  
    expect(meal).to receive(:update_attributes).once
    expect(OrderServicer).to receive(:add_meal_to_order).once
    expect(CRM).to receive(:update_customer_record).once
  end
  </code></pre>
  
  <p>Is there another way to test this thoroughly and meaningfully, other than instantiating actual meal, customer, and order objects connected appropriately (and possibly saved to the datbase), and then check that MealServicer.serve_meal(...) updates the object properties as expected? This will end up saving to the database eventually, because update_attributes does a save call and so do several of the methods I intend to include in my Service object method.</p>
  
  <p>Lastly because the tests depend on the implementation, I cannot write the tests before the method, which is what TDD advocates recommend. This just feels backwards. Any advice on writing performant but useful tests? </p>