You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rspec控制器测试中Stub map_typeform_response报错问题排查

关于Typeform响应获取测试中Stub方法与NilClass错误的排查

问题描述

我正在测试控制器的fetch_typeform_response方法,尝试Stub涉及外部API的:getResponse和:map_typeform_response方法,但运行测试时出现错误:HealthProfile does not implement #map_typeform_response。移除Stub代码后,又出现map_typeform_response方法内部的NoMethodError(undefined method '[]' for nil:NilClass),确认该方法确实被调用了,想请教这是什么原因?

相关代码

控制器方法

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

测试代码

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

错误原因分析与解决方案

1. 第一个错误:HealthProfile does not implement #map_typeform_response

你在测试中Stub的是HealthProfile的实例方法,但控制器里调用的HealthProfile.map_typeform_response(response)是一个类方法!这就是报错的核心原因——Stub的方法类型完全不匹配。

解决方案:
把实例方法的Stub改为类方法的Stub:

# 替换原来的allow_any_instance_of代码
allow(HealthProfile).to receive(:map_typeform_response).and_return(new_hp_after_mapping)

2. 第二个错误:undefined method '[]' for nil:NilClass

移除Stub后出现这个错误,主要有两个可能的诱因:

  • 测试数据结构不符:你Stub的getResponse返回的items里是HealthProfile实例,而真实的Typeform API返回的应该是哈希结构。当map_typeform_response尝试用[]访问这个实例的属性时,自然会触发错误。
  • 真实API返回异常:如果没有Stub,form.getResponse可能返回nil,或者返回的哈希中items为空,导致response['items'].first变成nil,传入map_typeform_response后触发nil的[]调用错误。

解决方案:

  • 修正测试中的模拟数据,确保返回符合真实API结构的哈希:
    allow_any_instance_of(TypeformService).to receive(:getResponse).and_return({ 
      'total_items': 1, 
      'items': [ 
        { 
          # 这里填充和真实Typeform响应一致的键值对,比如"answers": [...], "respondent_id": "xxx"等
        } 
      ] 
    }.as_json)
    
  • 在map_typeform_response类方法中添加nil检查,提前拦截无效输入:
    def self.map_typeform_response(response)
      return nil unless response.present?
      # 后续的映射逻辑
    end
    
  • 在控制器中增加对getResponse返回值的校验,避免后续处理nil:
    response = form.getResponse("query=#{ hp[:id] }")
    unless response.present?
      redirect_to health_profiles_path, notice: "Failed to fetch Typeform response."
      return
    end
    

内容的提问来源于stack exchange,提问作者Jeremy Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:58:27