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

如何用RSpec测试Rails中自定义select查询的返回结果?

问题描述

在Rails应用中执行以下聚合查询:

sums = OrderItem.where(id: oiids).select("sum(quantity_shipped) as quantity_shipped_sum, sum(price) as price_sum, sum(discount) as discount_sum, tenant_id").first

查询返回的对象可调用quantity_shipped_sum、price_sum、discount_sum这些动态生成的属性,但这些属性并非OrderItem模型的固有属性。

使用RSpec编写测试时,持续报错:OrderItem does not implement quantity_shipped_sum。尝试过两种Mock方式均失败,推测问题出在当前Mock的是OrderItem类,而where方法返回的是集合/关联对象。

解决方案

1. Mock完整查询调用链

where返回的是ActiveRecord::Relation对象,后续的select和first都基于这个关系对象执行,因此需要Mock整个调用链的返回值:

# 构建模拟的聚合结果对象
mock_sums = OpenStruct.new(
  quantity_shipped_sum: 10,
  price_sum: 100.0,
  discount_sum: 15.0,
  tenant_id: 1
)

# 依次Mock where -> select -> first 的调用
allow(OrderItem).to receive(:where).with(id: oiids).and_return(
  double("ActiveRecord::Relation", select: double(first: mock_sums))
)

2. 给OrderItem实例添加动态属性Stub

创建OrderItem实例后,手动为其添加动态属性的访问方法,再Mock查询链返回该实例:

sums = OrderItem.new
sums.define_singleton_method(:quantity_shipped_sum) { 10 }
sums.define_singleton_method(:price_sum) { 100.0 }
sums.define_singleton_method(:discount_sum) { 15.0 }
sums.tenant_id = 1

allow(OrderItem).to receive_message_chain(:where, :select, :first).and_return(sums)

3. 结合FactoryBot模拟(若项目已使用)

如果项目依赖FactoryBot,可以在工厂中定义带动态属性的实例:

factory :order_item_sum, class: OrderItem do
  transient do
    quantity_shipped_sum { 10 }
    price_sum { 100.0 }
    discount_sum { 15.0 }
  end

  after(:build) do |item, evaluator|
    item.define_singleton_method(:quantity_shipped_sum) { evaluator.quantity_shipped_sum }
    item.define_singleton_method(:price_sum) { evaluator.price_sum }
    item.define_singleton_method(:discount_sum) { evaluator.discount_sum }
  end
end

# 测试中调用
allow(OrderItem).to receive_message_chain(:where, :select, :first).and_return(build(:order_item_sum))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:42:39