RSpec报错:nil:NilClass未定义`expectation_fulfilled?`方法
expectation_fulfilled?错误 我之前也碰到过类似的RSpec模拟Cequel模型时的奇怪内部错误,结合你的场景咱们来一步步捋清楚解决方案:
首先明确你的核心需求:要模拟一个Relation对象,让它满足object.present? && object.deleted_at.nil?的判断条件,但用普通double或者手动创建对象的方式触发了RSpec内部的NoMethodError。这个错误本质是普通模拟方式和RSpec的期望链机制冲突,或者没有贴合Cequel Record的类结构导致的。
推荐的两种解决方案
1. 使用instance_double(最安全的模拟方式)
RSpec的instance_double会严格校验你模拟的方法是否在真实的Relation类中存在,能避免很多意外的方法冲突,完美适配你的场景:
# 在RSpec示例中定义模拟对象 let(:valid_relation) { instance_double(Relation, deleted_at: nil, present?: true) }
这样模拟出来的对象不仅能满足present?为true、deleted_at为nil的条件,还不会触发RSpec内部的方法错误——因为它只会模拟真实类中存在的方法,不会干扰RSpec的内部机制。
2. 直接创建真实的模型实例(最简单的方式)
如果你的测试场景不需要完全隔离数据库(或者Cequel允许创建未持久化的实例),直接创建真实的Relation实例反而更省心:
let(:valid_relation) { Relation.new(deleted_at: nil) }
未持久化的Cequel Record实例本身就满足present?为true(对象非nil),再加上你显式设置了deleted_at为nil,完全符合判断条件,同时不会有任何模拟相关的冲突问题。
为什么原来的方式会出错?
你之前用普通double或者手动赋值的方式,可能不小心覆盖了RSpec内部依赖的方法(比如和期望链相关的方法),导致RSpec在处理期望时出现chains.last为nil的情况,进而触发undefined method 'expectation_fulfilled?' for nil:NilClass错误。而instance_double会严格限制模拟的方法范围,真实实例则完全绕过了模拟的问题,这两种方式都能避开这个陷阱。
内容的提问来源于stack exchange,提问作者somenickname

