如何用RSpec模拟MangoPay外部API调用并返回指定响应?
嘿,我来帮你搞定这个RSpec模拟MangoPay API调用的事儿!要在测试里跳过真实的外部API请求,同时让它返回你想要的响应,其实用RSpec的mock功能就能轻松实现。下面是具体的实现步骤和示例代码:
RSpec模拟MangoPay API调用指南
1. 基础思路
我们需要模拟MangoPay::PayOut::BankWire.create这个类方法,让它在测试时不发起真实请求,而是直接返回你预设的响应数据(或者抛出异常模拟错误场景)。因为wallet_to_bank是after_save回调,所以只要在调用transaction.save前设置好模拟,就能覆盖到回调里的API调用。
2. 模拟成功响应的测试示例
假设你的测试文件是spec/models/transaction_spec.rb,可以这么写:
require 'rails_helper' RSpec.describe Transaction, type: :model do # 预先定义模拟的MangoPay响应数据,和真实API返回格式一致 let(:mock_payout_response) do { 'Id' => 'pay_out_789', 'Status' => 'SUCCEEDED', 'DebitedFunds' => { 'Currency' => 'USD', 'Amount' => 5000 }, 'CreatedDate' => Time.now.to_i } end it 'triggers wallet_to_bank after save and uses mocked MangoPay response' do # 先准备测试用的关联对象(比如receiver_wallet) receiver_wallet = create(:wallet) # 假设用FactoryBot创建钱包实例 transaction = build(:transaction, receiver_wallet: receiver_wallet) # 设置模拟:当调用MangoPay的create方法时,返回我们预设的响应 # 用hash_including来灵活匹配参数,不用完全写死所有字段 allow(MangoPay::PayOut::BankWire).to receive(:create) .with( hash_including( 'AuthorId' => receiver_wallet.provider_user_id, 'DebitedWalletId' => receiver_wallet.provider_wallet_id, 'DebitedFunds' => hash_including('Currency' => transaction.currency) ) ) .and_return(mock_payout_response) # 触发save,这会自动调用after_save里的wallet_to_bank transaction.save # 可选:验证API方法确实被调用了,确保回调正常触发 expect(MangoPay::PayOut::BankWire).to have_received(:create) # 如果你的Transaction类会把MangoPay返回的ID存下来,可以加这个断言 # expect(transaction.mangopay_payout_id).to eq('pay_out_789') end end
3. 模拟API错误的场景
要是你想测试API调用失败的情况(比如网络错误、API返回500),可以模拟方法抛出异常:
it 'handles MangoPay API failures gracefully' do transaction = build(:transaction) # 模拟API调用抛出异常,这里用MangoPay官方的错误类 allow(MangoPay::PayOut::BankWire).to receive(:create) .and_raise(MangoPay::Error.new('Insufficient funds', 400)) # 验证保存操作不会崩溃(前提是你在wallet_to_bank里捕获了异常) expect { transaction.save }.to_not raise_error # 还可以断言错误日志是否被记录,比如用rspec-rails的日志匹配器 # expect(Rails.logger).to have_logged(/Insufficient funds/) end
几个关键注意点
- 灵活匹配参数:用
hash_including可以避免因为参数里有动态值(比如金额)导致匹配失败,如果你需要严格匹配参数,直接传入完整的参数哈希就行。 - 模拟时机:一定要在调用
transaction.save之前设置好模拟,不然回调触发时模拟还没生效,会调用真实的API。 - 验证调用:用
have_received(:create)可以确保回调确实触发了API调用,避免漏测。
内容的提问来源于stack exchange,提问作者Mike W
相关产品推荐
相关产品推荐

