I found a solution to make it work: I override render method in 
FakeController as follows:

require 'rails_helper'


class FakeController < ApplicationController
  
  def render(*args)
    args.first
  end
end


RSpec.describe FakeController, type: :controller do
  it_should_behave_like "JSON Responsive controller", FakeController
end

And to test one of Response module methods, here is how I proceed:

context '#respond_with_errors' do    
    it 'returns :unprocessable_entity status' do
      model = double(:model)
      errors = double(:errors, messages: {})
      allow(model).to receive(:errors).and_return(errors)
      response = instance.respond_with_errors(model)
      expect(response[:status]).to eq :unprocessable_entity
    end
  end




On Wednesday, 27 February 2019 16:47:39 UTC+1, belgoros wrote:
>
>
>
> On Wednesday, 27 February 2019 16:19:16 UTC+1, belgoros wrote:
>>
>>
>>
>> On Wednesday, 27 February 2019 16:05:18 UTC+1, belgoros wrote:
>>>
>>>
>>>
>>> On Wednesday, 27 February 2019 16:02:23 UTC+1, Jon Rowe wrote:
>>>>
>>>> You need to include your concern in your fake controller.
>>>>
>>>> We do have the anonymous controller helpers for this purpose. See: 
>>>> https://relishapp.com/rspec/rspec-rails/docs/controller-specs/anonymous-controller
>>>>
>>>> Although you’ll still need to include the concern.
>>>>
>>>
>>> Weird, I have it defined as follows without including the module 
>>> Response as it was included in ApplicationController:
>>>
>>> require 'rails_helper'
>>>
>>>
>>> class FakeController < ApplicationController
>>> end
>>>
>>>
>>> RSpec.describe FakeController, type: :controller do  
>>>   it_should_behave_like "JSON Responsive controller" do 
>>>     let(:instance) { FakeController.new }
>>>   end
>>>
>>> end 
>>>
>>>>
>>>> Cheers
>>>> Jon Rowe
>>>> ---------------------------
>>>> [email protected]
>>>> jonrowe.co.uk
>>>>
>>>> On 27 February 2019 at 13:25, belgoros wrote:
>>>>
>>>> On Wednesday, 27 February 2019 14:08:53 UTC+1, belgoros wrote:
>>>>
>>>>
>>>>
>>>> On Wednesday, 27 February 2019 12:02:12 UTC+1, Jon Rowe wrote:
>>>>
>>>> If you need a controller you need a controller spec, its not practical 
>>>> to instantiate a controller on your own, one of the many reasons why they 
>>>> are recommended against by the Rails team now.
>>>>
>>>> Otherwise you need to test the behaviour of the end result, e.g. create 
>>>> a set of shared examples for your concern and use them in every 
>>>> request/system/integration test for the routes concerned.
>>>>
>>>>
>>>> I tried it as follows:
>>>>
>>>> #spec/controllers/concerns/response_spec.rb
>>>> require 'rails_helper'
>>>> class FakeController < ApplicationController
>>>> end
>>>> RSpec.describe FakeController, type: :controller do
>>>>
>>>>   let
>>>> (:controller) { FakeController.new}
>>>>
>>>>   
>>>>   
>>>> FakeModel = Struct.new(:name)
>>>>
>>>>   describe 
>>>> 'Response concern' do
>>>>
>>>>     context 
>>>> '#json_response' do
>>>>
>>>>       it 
>>>> 'renders JSON response' do
>>>>
>>>>         fake_model 
>>>> = FakeModel.new('example')
>>>>
>>>>         result 
>>>> = controller.json_response(fake_model)
>>>>
>>>>         puts 
>>>> "result: #{result.inspect}"
>>>>        
>>>>       
>>>> end
>>>>
>>>>     
>>>> end
>>>>
>>>>     
>>>>   
>>>> end
>>>> end
>>>>
>>>> but it fails with:
>>>>
>>>> rspec spec/controllers/concerns/response_spec.rb 
>>>>
>>>> F
>>>>
>>>> Failures:
>>>>
>>>>   1) FakeController Response concern #json_response renders JSON 
>>>> response
>>>>
>>>>      Failure/Error: render response
>>>>
>>>>      
>>>>
>>>>      Module::DelegationError:
>>>>
>>>>        ActionController::Metal#status= delegated to 
>>>> @_response.status=, but @_response is nil: 
>>>> #<FakeController:0x00007fd004810700 @_routes=nil, @_request=nil, 
>>>> @_response=nil, @_config={}, @_db_runtime=109.12200000000001>
>>>>
>>>>      # ./app/controllers/concerns/response.rb:6:in `json_response'
>>>>
>>>>      # ./spec/controllers/concerns/response_spec.rb:14:in `block (4 
>>>> levels) in <top (required)>'
>>>>
>>>>      # ------------------
>>>>
>>>>      # --- Caused by: ---
>>>>
>>>>      # NoMethodError:
>>>>
>>>>      #   undefined method `status=' for nil:NilClass
>>>>
>>>>      #   ./app/controllers/concerns/response.rb:6:in `json_response'
>>>>
>>>> Finished in 0.17825 seconds (files took 1.12 seconds to load)
>>>>
>>>> 1 example, 1 failure
>>>>
>>>>
>>>> What am I missing here ?
>>>>
>>>>
>>>> I modified by creating a shared example as follows:
>>>>
>>>> #spec/shared/json_response.rb
>>>> require 'rails_helper'
>>>> RSpec.shared_examples 'JSON Responsive controller' do |controller_class
>>>> |
>>>>
>>>>   let
>>>> (:controller_class) { including_class.new }
>>>>
>>>>
>>>>
>>>>   it 
>>>> 'render JSON response' do
>>>>
>>>>     expect
>>>> (controller_class).to respond_to(:json_response)
>>>>
>>>>   
>>>> end
>>>> end
>>>>
>>>>
>>>> Then by using it in a controller spec:
>>>> #spec/controllers/concerns/fake_controller_spec.rb
>>>> require 'rails_helper'
>>>> class FakeController < ApplicationController
>>>> end
>>>> RSpec.describe FakeController, type: :controller do
>>>>
>>>>   it_behaves_like 
>>>> 'JSON Responsive controller', FakeController
>>>> end
>>>>
>>>>
>>>> But it fails as follows:
>>>>
>>>> Failures:
>>>>
>>>>   1) FakeController behaves like JSON Responsive class render JSON 
>>>> response
>>>>
>>>>      Failure/Error: expect(controller_class).to respond_to(
>>>> :json_response)
>>>>
>>>>        expected FakeController to respond to :json_response
>>>>
>>>>      Shared Example Group: "JSON Responsive class" called from 
>>>> ./spec/controllers/concerns/fake_controller_spec.rb:7
>>>>
>>>>      # ./spec/shared/json_response.rb:7:in `block (2 levels) in <main>'
>>>>
>>>>
>> The error is due the call render response in Response module:
>> def json_response(object, status = :ok, opts = {})
>>     response = {json: object, status: status}.merge(opts)
>>     puts "++++++++ response: #{response.inspect}"
>>     render response
>>   end
>>
>> The 'puts' displays:
>>
>> ++++++++ response: {:json=>#<Double :model>, :status=>:ok}
>>
>>  
>> But the error says is related to Module::DelegationError:
>>
>> Module::DelegationError: 
>>
>> ActionController::Metal#status= delegated to @_response.status=, but 
>> @_response is nil: #<FakeController:0x00007faf08fe0920 @_routes=nil, 
>> @_request=nil, @_response=nil, @_config={}, @_db_runtime=181.55> 
>>
>> Shared Example Group: "JSON Responsive controller" called from ./spec/
>> controllers/concerns/fake_controller_spec.rb:7 
>>
>> # ./app/controllers/concerns/response.rb:7:in `json_response' 
>>
>> # ./spec/shared/json_response.rb:13:in `block (3 levels) in <main>' 
>>
>> # ------------------ 
>>
>> # --- Caused by: --- 
>>
>> # NoMethodError: 
>>
>> # undefined method `status=' for nil:NilClass 
>>
>> # ./app/controllers/concerns/response.rb:7:in `json_response'
>>
>
> Finally, the version that works:
>
> #spec/shared/json_response.rb
>
>
> require 'rails_helper'
>
>
> RSpec.shared_examples 'JSON Responsive controller' do |
> including_controller|
>   let(:instance) { including_controller.new }
>
>
>   it 'should respond to #json_response' do
>     expect(instance).to respond_to(:json_response)
>   end
>
>
>   it 'should respond #respond_with_errors' do
>     expect(instance).to respond_to(:respond_with_errors)
>   end
>   
>   it 'should respond to #paginated_response_status' do
>     expect(instance).to respond_to(:paginated_response_status)
>   end
>
>
>   context '#paginated_response_status' do   
>     it 'return 200 if collection is not paginated' do
>       expect(instance.paginated_response_status([1])).to eq :ok
>     end
>
>
>     it 'return 206 if collection is paginated' do
>       collection = (1..35).to_a
>       expect(instance.paginated_response_status(collection)).to eq :
> partial_content
>     end
>   end
> end
>
>
>
> It will fail if I try to call *Response* module methods that call *render* 
> inside. Can't figure out how to get around if it.
>
>>
>>  
>>>>
>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rspec/555434f0-6dec-4d6d-8661-75b74ed116c8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to