我们在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
字符串
在这个select
之后,我们可以在返回的Association
上执行sums.quantity_shipped_sum
。
如何在Rspec中用这个来编写测试?我所做的一切都告诉我OrderItem does not implement quantity_shipped_sum
或类似的错误。需要明确的是,quantity_shipped_sum
不是OrderItem
上的方法/属性,它只是由这个select创建的。
我试过了
allow(OrderItem).to receive(:quantity_shipped_sum).and_return(2)
型
和/或
allow(OrderItem).to receive(:first).and_return(instance_double(OrderItem, quantity_shipped_sum: 2, price_sum: 10.0, discount_sum: 1.0, tenant_id: 1))
型
对于更多的上下文,这里是一些更多的spec
文件:
allow(OrderItem).to receive(:where).and_return(OrderItem)
allow(OrderItem).to receive(:select).and_return(OrderItem)
allow(OrderItem).to receive(:distinct).and_return(OrderItem)
allow(OrderItem).to receive(:pluck).and_return([order_item1.id, order_item2.id])
allow(OrderItem).to receive(:first).and_return(instance_double(OrderItem, quantity_shipped_sum: 2, price_sum: 10.0, discount_sum: 1.0, tenant_id: 1))
型
我想我知道为什么这些失败了--因为它们在类上,而where
返回一个集合/关联。
1条答案
按热度按时间7nbnzgx91#
有几个问题。让我们从这里开始:
你的代码是这样做的:
字符串
此代码对
order_items
表执行SQLSELECT
语句,返回包含OrderItem
示例的ActiveRecord::Relation
示例,然后获取Relation
中的第一个OrderItem
示例。您的测试存根正在执行以下操作:
型
这将正确地存根
where
方法。但是,返回OrderItem类,而不是ActiveRecord::Relation
的示例。所以,现在,当代码执行时,select
将被调用到OrderItem
类。这看起来是可行的,因为OrderItem
继承了ActiveRecord::Base
,而ActiveRecord::Base
确实有一个select
方法。但严格来说这是不正确的。所有
allow(OrderItem)
语句都是如此。真实的的问题在这里:
型
在代码中,
first
是在ActiveRecord::Relation
的示例上调用的。在allow
语句指定的OrderItem
类上不调用它。RSpec不会抛出错误,因为OrderItem
继承自ActiveRecord::Base
,而ActiveRecord::Base
恰好包含first
方法(如上所述)。但是,OrderItem
没有名为quantity_shipped_sum
、price_sum
或discount_sum
的方法。RSpec的instance_double
方法只允许您使用实际出现在类定义中的存根方法。我觉得你其实想要这样的东西:
型
请注意,
instance_double
不使用OrderItem
类。这将启用RSpec的特性,该特性验证类中是否存在存根方法。通过使用字符串"order item"
,可以禁用该功能。同样需要注意的是,这种语法不允许您验证传入
where
和select
的任何参数。你得做不同的测试。最后,为了避免不可避免的评论,你不应该使用
receive_message_chain
,我会说,一般的指导是,receive_message_chain
被认为是一种气味,因为它允许你相当容易地违反Law of Demeter。这是ActiveRecord。ActiveRecord使用fluent interface将方法链接在一起。这些方法链不被认为违反了得墨忒耳定律。这是框架的一个特点。