Ruby on Rails的Array.include?是否仅校验对象引用而非对象内容?
问题解答
首先明确结论:Ruby原生的Array#include?方法默认通过==运算符判断元素是否匹配,普通自定义类的==运算符默认校验对象引用身份(即object_id是否相同),不会主动对比对象的属性值。你遇到的测试失败就是因为expected_bubble和数组中属性一致的Bubble对象是两个不同实例,object_id不同,所以判断为不匹配。
可行解决方案
方案1:重写DTO类的==方法
在Soda::DTO::Bubble类中自定义==的对比规则,指定需要校验的属性:
class Soda::DTO::Bubble def ==(other) return false unless other.is_a?(self.class) container_id == other.container_id && bubble_type == other.bubble_type && flavor_id == other.flavor_id && bubble_sid == other.bubble_sid && id == other.id && desc == other.desc end end
修改后原生Array#include?和RSpec的include匹配器都会按属性对比判断是否匹配。
方案2:使用RSpec属性匹配语法(无需修改业务代码)
不需要修改DTO类定义,直接在测试中用an_object_having_attributes匹配器:
# 直接传入要匹配的属性 expect(bubble_dtos).to include( an_object_having_attributes( container_id: 594, bubble_type: "co2", flavor_id: 3528, bubble_sid: "soda::bubble:dbid/1421", id: 1421, desc: "desc3" ) ) # 如果已有expected_bubble对象,也可以直接读取它的属性 expect(bubble_dtos).to include(an_object_having_attributes(expected_bubble.attributes))
方案3:转哈希后对比
将所有对象转为属性哈希后再判断是否包含:
expect(bubble_dtos.map(&:attributes)).to include(expected_bubble.attributes)
补充说明
如果你的DTO是通过Ruby的Struct或Data类定义的,它们默认已经实现了按属性对比的==方法,不会出现这类问题,只有普通自定义类默认按引用对比。
内容的提问来源于stack exchange,提问作者HeyThere
相关产品推荐
相关产品推荐

