Rspec 控制器规范声明函数 ios 未调用

Rspec controller spec claims function ios not called

我正在测试我的一个控制器,并试图存根函数调用,但没有成功。这是函数:

def fetch_typeform_response
    hp = HealthProfile.find(params[:id])
    form = TypeformService.new('x')
    response = form.getResponse("query=#{ hp[:id] }")

    if response['total_items'] != 1
        if response[:response_id].present?
            response = form.getResponse("included_response_ids=#{ hp[:response_id] }")
        end
    end

    if response['total_items'] == 1

        response = response['items'].first
        health_profile = HealthProfile.map_typeform_response(response)

        if health_profile.save
            health_profile.reload
            redirect_to health_profile_path(health_profile), notice: "Successfully updated the health profile response."
            return
        end

    end

    redirect_to health_profiles_path, notice: "We could not locate the health profile."
end

在我的测试中,我去掉了 :getResponse:map_typeform_response,因为它们涉及外部 API:

it "expects to fetch typeform response" do
  new_hp = build(:health_profile)
  new_hp_after_mapping = build(:health_profile)

  allow_any_instance_of(TypeformService).to receive(:getResponse).and_return({ 'total_items': 1, 'items': [ new_hp ] }.as_json)
  allow_any_instance_of(HealthProfile).to receive(:map_typeform_response).and_return(new_hp_after_mapping)

  get :fetch_typeform_response, params: { id: @hp.id }
  expect(response).to redirect_to(health_profile_path(@hp.id))
end

但我收到错误消息:HealthProfile does not implement #map_typeform_response

如果删除存根行,我会看到错误:

Failure/Error: p "Using health_profile_id: #{response['hidden']['id']}"

     NoMethodError:
       undefined method `[]' for nil:NilClass

它发生在 :map_typeform_response 函数内部(很明显它被调用了!)。知道为什么会发生这种情况吗?

您正在 class HealthProfile 而不是 class 的实例上调用 map_typeform_response 方法。

改变

allow_any_instance_of(HealthProfile).to receive(:map_typeform_response).and_return(new_hp_after_mapping)

allow(HealthProfile).to receive(:map_typeform_response).and_return(new_hp_after_mapping)

发生这种情况是因为 rspec 阻止您模拟或存根一个在真实对象上不存在的方法。默认为真,因为 Rails 4.

RSpec.configure do |config|
  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
end

更多建议

我还建议将 new_hpnew_hp_after_mapping 变量的构建移动到 let

let(:new_hp) { build(:health_profile) }
let(:new_hp_after_mapping) { build(:health_profile) }

将存根移动到 before

before do
  allow_any_instance_of(TypeformService).to receive(:getResponse).and_return({ 'total_items': 1, 'items': [ new_hp ] }.as_json)
  allow(HealthProfile).to receive(:map_typeform_response).and_return(new_hp_after_mapping)
end

所以你的测试看起来像

it "expects to fetch typeform response" do
  # make sure variable @hp intialized in your test.
  get :fetch_typeform_response, params: { id: @hp.id }
  expect(response).to redirect_to(health_profile_path(@hp.id))
end