Search code examples
ruby-on-railsrspecrspec-rails

How to stub a method from a module in a controller?


lib/modules/api.rb:

module Api
  require 'net/http'
  require 'json'

  def send_get_request(url, body)
    # some logic
  end
end

The controller:

class DashboardController < ApplicationController
  include Api

  def index
    response = send_get_request(_some_, _params_)[:json]
    @something = response['something']
  end
end

How do I stub the send_get_request method? I tried a feature test:

require 'rails_helper'

describe 'visiting users page' 
  it 'shows users page' do
    visit '/'
    allow_any_instance_of(Api).to receive(:send_get_request).with(any_args).and_return({json: {'total_paying' => '3'}})
    within('#side-menu') do
      click_link 'Users'
    end
    expect(page).to have_selector('.page-header', text: 'Users')
  end
end

but apparently it doesn't work (the test fails because real send_get_request method gets called with params that are incorrect (which they are in tests).

When I tried

expect_any_instance_of(Api).to receive(:send_get_request).once

That expectation passed.


Solution

  • Well, it's the controller that will receive the message. The test, as a client, does not care about how the method is defined, "normally" or mixed-in.

    If it were a controller spec, you'd be able to do this:

     allow(controller).to receive(:send_get_request).with(...)
    

    As for the feature specs, don't stub anything in there. It's supposed to be the "real" interaction. In feature specs you use capybara (or something) to fill the forms and then check the database (to see if a user got created, etc.)

    To shield your feature specs from external api, you can use VCR gem. It basically runs your external query one time, writes the response into a file and then, on subsequent runs, just plays it back, without contacting external api again.