title: How to test controller without hitting the database?
body: <p>I have a controller:</p>
  
  <pre><code>class InvoicesController &lt; ApplicationController
    def edit
      @invoice = Invoice.includes(:client, :document_status).find(params[:id])
      return head :forbidden unless @invoice.editable?
    end
  end
  </code></pre>
  
  <p>I want to write a test but without hitting the database:</p>
  
  <pre><code>describe InvoicesController do
    describe '#edit' do
      let(:invoice_id) { '1' }
      let(:invoice) { double(Invoice, editable?: false) }
      let(:invoice_includes) { double }
  
      before do
        allow(invoice_includes).to receive(:find).with(invoice_id) { invoice }
        allow(Invoice).to receive(:includes).with(:client, :document_status) { invoice_includes }
      end
  
      subject { get :edit, params: {id: invoice_id} }
  
      it { is_expected.to have_http_status(403) }
    end
  end
  </code></pre>
  
  <p>Is there a better approach? I don't like this chain of <code>allow</code>s but I can't think of anything better. Setting the <code>@invoice</code> instance variable in the test would be bad, because then I would rely on the implementation.</p>
  
  <p>I could obviously just create the invoice in the DB and don't bother about all the mocks and stubs. However, doing this in all the specs would slow down the whole test suite.</p>