Rails 7中Faraday测试Stub报错Faraday::Adapter::Test::Stubs::NotFound
你遇到的Faraday::Adapter::Test::Stubs::NotFound错误,核心原因是Stub路径与实际请求路径不匹配,同时代码里还有几处逻辑问题需要修正,具体解决步骤如下:
1. 修正Stub路径(核心问题)
FakeClient的connection已经设置了url_prefix = BASE_URL(即https://test-api.net/api/v1/),当调用get("merchants/#{platform_merchant_id}/payouts")时,实际请求的路径是/merchants/1234/payouts(url_prefix会自动拼接)。但你的测试Stub写了api/v1/merchants/#{platform_merchant_id}/payouts,导致路径重复,无法匹配。
修复测试代码中的Stub定义:
let(:stub) do Faraday::Adapter::Test::Stubs.new do |stub| # 去掉前面的api/v1,直接写相对路径 stub.get("merchants/#{platform_merchant_id}/payouts") do [200, { 'Content-type' => 'application/json' }, 'test response'] end end end
2. 修复Resource类的递归调用问题
Resource类的initialize方法里写了@client = client,而client方法中又会判断@client ||= ...,这会导致无限递归调用,同时无法正确传递@stubs参数。
修改Resource类:
module Isor class Resource def initialize(stubs: nil) @stubs = stubs @client = client end def get(url, params: {}, headers: {}) handle_response client.connection.get(url, params, default_headers.merge(headers)) end # (...) 其他HTTP方法 private def client return @client ||= Client.new unless Rails.env.test? @client ||= FakeClient.new(stubs: @stubs) end def default_headers { Authorization: "Bearer #{client.api_key}" } end def handle_response(response) return response.body if response.success? # (...) 错误处理代码 end end end
3. 让FakeClient传递Stubs给Accounts资源
FakeClient的accounts方法当前返回Resources::Accounts.new,没有传递自身的@stubs,导致Accounts实例无法使用测试中传入的Stub。
修改FakeClient的accounts方法:
module Isor class FakeClient # (...) 其他代码 def accounts Resources::Accounts.new(stubs: @stubs) end # (...) 其他代码 end end
4. 修正测试用例的参数传递错误
测试里的subject.payout_history(platform_merchant_id:)语法错误,需要传递具体的参数值。
修改测试用例:
describe '#payout_history' do it 'returns payout history' do expect(subject.payout_history(platform_merchant_id: platform_merchant_id)).to eq('test response') end end
完成以上修复后,测试应该能正确匹配Stub并返回预期结果。
内容的提问来源于stack exchange,提问作者mr_muscle

