如何从控制器中的模块存根方法?

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

控制器:

class DashboardController < ApplicationController
  include Api

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

如何存根 send_get_request 方法?我尝试了功能测试:

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

但显然它不起作用(测试失败,因为真正的 send_get_request 方法被调用时使用了不正确的参数(它们在测试中)。

当我尝试时

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

这个期望过去了。

嗯,接收消息的是控制器。测试,作为client,并不关心method是怎么定义的,"normally" or mixed-in.

如果它是控制器规格,您可以这样做:

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

至于功能规范,请不要在其中添加任何内容。它应该是 "real" 交互。在功能规范中,您使用水豚(或其他东西)填写表格,然后检查数据库(查看是否创建了用户等)

要保护您的功能规范不受外部影响 api,您可以使用 VCR gem。它基本上运行您的外部查询一次,将响应写入文件,然后在后续运行中回放,无需再次联系外部 api。