如何在RSPEC中Stub ShopifyAPI::DraftOrder的find/all方法并返回静态哈希
模拟ShopifyAPI::DraftOrder返回静态数据的正确方式
你遇到的问题核心在于:ShopifyAPI的DraftOrder是ActiveResource模型,它的find/all方法返回的是模型实例(或实例数组),而非普通Ruby哈希。直接返回哈希会导致后续代码调用实例方法(比如.id、.attributes)时抛出NoMethodError,这就是你的mock没生效的关键原因。
下面是两种可行的实现方案:
方案一:使用模拟实例(Double)
适合需要精细控制实例方法返回值的场景:
# 1. 定义你的静态哈希数据 static_draft_order_hash = { id: 123, name: "Draft Order #1", email: "customer@example.com", # 其他你需要的字段 } # 2. 创建模拟的DraftOrder实例 mock_draft_order = double("ShopifyAPI::DraftOrder") # 模拟attributes方法返回静态哈希 allow(mock_draft_order).to receive(:attributes).and_return(static_draft_order_hash) # 如果你的代码直接调用实例属性(比如`.id`、`.name`),单独模拟这些方法 allow(mock_draft_order).to receive(:id).and_return(static_draft_order_hash[:id]) allow(mock_draft_order).to receive(:name).and_return(static_draft_order_hash[:name]) # 3. 模拟find方法返回这个实例 allow(ShopifyAPI::DraftOrder).to receive(:find).with(draft_id).and_return(mock_draft_order)
对于all方法(返回实例数组):
# 定义多个静态哈希 draft_order_hashes = [ { id: 123, name: "Order 1" }, { id: 456, name: "Order 2" } ] # 创建模拟实例数组 mock_draft_orders = draft_order_hashes.map do |hash| mock = double("ShopifyAPI::DraftOrder") allow(mock).to receive(:attributes).and_return(hash) allow(mock).to receive(:id).and_return(hash[:id]) mock end # 模拟带参数的all调用 allow(ShopifyAPI::DraftOrder).to receive(:all).with(params: {page: 1, status: 'any'}).and_return(mock_draft_orders) # 模拟不带参数的all调用 allow(ShopifyAPI::DraftOrder).to receive(:all).and_return(mock_draft_orders)
方案二:直接实例化ShopifyAPI::DraftOrder
如果不需要精细控制方法,直接用真实的模型实例更简单:
# 1. 定义静态哈希 static_draft_order_hash = { id: 123, name: "Draft Order #1" } # 2. 创建DraftOrder实例并赋值属性 mock_draft_order = ShopifyAPI::DraftOrder.new(static_draft_order_hash) # 模拟find方法 allow(ShopifyAPI::DraftOrder).to receive(:find).with(draft_id).and_return(mock_draft_order) # 对于all方法,返回实例数组 mock_draft_orders = [ ShopifyAPI::DraftOrder.new({ id: 123, name: "Order 1" }), ShopifyAPI::DraftOrder.new({ id: 456, name: "Order 2" }) ] allow(ShopifyAPI::DraftOrder).to receive(:all).with(params: {page: 1, status: 'any'}).and_return(mock_draft_orders)
额外排查点
如果按照上面的方式还是没生效,检查以下两点:
- 参数匹配是否完全一致:比如
all方法的params里的键值对是否和实际调用完全相同(比如page是整数还是字符串?有没有额外的参数?)。RSpec的with是严格匹配的,参数不匹配会导致mock不触发,转而调用真实API。 - 是否有重复的mock:如果之前已经对
ShopifyAPI::DraftOrder的方法做过mock,后面的mock可能会被覆盖或者冲突,检查测试用例里的mock顺序。
内容的提问来源于stack exchange,提问作者aldrien.h
相关产品推荐
相关产品推荐

