4

I am writing a controller spec to verify this private method and I get the error Module::DelegationError: ActionController::RackDelegation but I am lost as how to fix this. The best example I have found has been http://owowthathurts.blogspot.com/2013/08/rspec-response-delegation-error-fix.html.

How can I get the unverified spec to pass? I want to make sure the 401 is returned.

Method

def validate_api_request
  return four_oh_one unless api_request_verified?(request)
end

Current Spec

describe Api::ApiController, type: :controller do
  describe '#validate_api_request' do
    it 'verified' do
      allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(true)
      expect(subject.send(:validate_api_request)).to be_nil
    end

    it 'unverified' do
      allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(false)
      allow(controller).to receive(:redirect_to)
      binding.pry
    end
  end
end

I'm using Rails 4.

halfer
  • 19,824
  • 17
  • 99
  • 186
Chris Hough
  • 3,389
  • 3
  • 41
  • 80
  • Maybe the problem is that you stub away the call to `redirect_to` and then the request ends up getting neither a render nor a redirect. Try `receive(:redirect_to).and_call_original`. – Raffael Jun 29 '16 at 22:25
  • @Raffael I solved this by the setup below, thoughts? – Chris Hough Jun 29 '16 at 22:28

1 Answers1

2

If anyone is working on a similar issue writing controller specs, here is how I solved this based on these 2 guides: http://codegur.com/22603728/test-user-authentication-with-rspec and https://gayleforce.wordpress.com/2012/12/01/testing-rails-before_filter-method/.

describe Api::ApiController, type: :controller do
  describe '#validate_api_request' do
    controller(Api::ApiController) do
      before_filter :validate_api_request
      def fake
        render text:  'TESTME'
      end
    end

    before do
      routes.draw { get 'fake', to: 'api/api#fake' }
    end

    it 'verified' do
      allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(true)
      expect(subject.send(:validate_api_request)).to be_nil
    end

    it 'unverified' do
      allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(false)
      get 'fake'
      expect(response.status).to be(401)
    end
  end
end
Chris Hough
  • 3,389
  • 3
  • 41
  • 80
  • You are now more strongly decoupling the test for the private method from a concrete controller method. This makes the test more concise. If this private method is used a lot throughout your application, then I love the new approach. Otherwise one might ask whether the added complexity is worth it. – Raffael Jun 29 '16 at 22:36
  • yep, it is used all over which is why I wanted to hit it hard :) thank you for your feedback – Chris Hough Jun 29 '16 at 22:37
  • If you do test that way, do it for all examples. I.e. change `it 'verified'` to invoke `get 'fake'`, too, and show that you expect `"TESTME"` to be rendered. – Raffael Jun 29 '16 at 22:38
  • Another approach would be to test the return value of the private method and then rely on the framework's behaviour to disrupt your request based on the return value. The approach you chose serves better as documentation, thoug. – Raffael Jun 29 '16 at 22:43
  • thank you so much for your help! would you have thoughts on http://stackoverflow.com/questions/38085404/rails-4-oauth-model-concern-test-coverage-stubs by chance? – Chris Hough Jun 30 '16 at 04:06
  • Glad it worked out for you :) Please accept and upvote my answer. – Raffael Jun 30 '16 at 13:55
  • there is only one answer on this question, and since I posted it I can not accept it until tomorrow. – Chris Hough Jun 30 '16 at 16:01