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

Rails中使用Webmock Stub API请求无效,返回真实数据问题排查

问题原因及解决方案

核心问题

WebMock 只能拦截 Ruby 进程发起的 HTTP 请求,但你的 React 前端是在浏览器环境中运行的,点击按钮后通过 fetch 发起的请求是浏览器直接发送的,不属于 Ruby 进程的请求范畴,所以 WebMock 的 stub 规则完全没起作用,自然会拿到真实的 API 数据。

解决方案

方案一:使用 puffing-billy 拦截浏览器请求

puffing-billy 是专门用于拦截 Capybara 驱动中浏览器发起的 HTTP 请求的工具,能完美解决这个场景的问题:

  1. 安装依赖
    在 Gemfile 的 test 组中添加:
group :test do
  gem 'puffing-billy'
end

执行 bundle install 完成安装。

  1. 配置 Capybara 驱动
    在 spec/support/billy.rb 中添加配置:
require 'billy/capybara/rspec'

# 替换你当前使用的 JS 驱动,比如原来是 :selenium_chrome_headless,就改成 :selenium_chrome_headless_billy
Capybara.javascript_driver = :selenium_billy
  1. 修改测试代码
    用 Billy 的 stub 规则替代 WebMock:
require 'rails_helper'

RSpec.describe 'visiting the embedded app', type: :system do
  it 'visits the embedded app' do
    # 用 Billy 拦截目标 API 请求并返回假数据
    Billy.stub('api_endpoint') do |stub|
      stub.to_return(
        status: 200,
        body: { data: 'dummy' }.to_json,
        headers: { 'Content-Type' => 'application/json' }
      )
    end

    visit 'my react page with the button'
    click_button "Call API"
    
    # 用 Capybara 内置的等待机制替代 sleep,确保请求完成后再断言
    expect(page).to have_content('dummy')
  end
end

方案二:调整前端请求指向本地代理(适合前端直接调用外部 API 的场景)

如果不想引入新 gem,可以修改前端在测试环境下的请求地址,让请求先经过 Rails 测试服务器,再由 Rails 用 WebMock 转发:

  1. 前端修改请求地址
    将 fetch("api_endpoint") 改为 fetch("/api/proxy")。

  2. 新增 Rails 代理控制器

# app/controllers/api/proxy_controller.rb
class Api::ProxyController < ApplicationController
  def index
    response = HTTP.get('真实的api_endpoint')
    render json: response.body, status: response.status
  end
end
  1. 测试中用 WebMock stub 控制器的外部请求
RSpec.describe 'visiting the embedded app', type: :system do
  it 'visits the embedded app' do
    stub_request(:get, '真实的api_endpoint').to_return(
      body: { data: 'dummy' }.to_json,
      headers: { 'Content-Type' => 'application/json' }
    )

    visit 'my react page with the button'
    click_button "Call API"
    expect(page).to have_content('dummy')
  end
end

额外优化点

  • 不要用 sleep 10 等待请求完成,Capybara 会自动等待断言条件满足,硬编码 sleep 会让测试变慢且不稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:00:38