我一直在努力诊断仅在我的主分支上发生的测试失败。以下是相关代码,为简化形式。
有一项服务:
class Service
attr_reader :traces
def initialize
@traces = []
end
def do_work
@traces << Thread.current.backtrace
# ... actual work ...
end
end
还有一个使用该服务的类:
class Widget
def get_cached_service
puts("Getting a cached service!")
puts("Do I already have one? #{!!@service}")
@service ||= make_service
end
def make_service
puts("Making a service!")
Service.new
end
end
我有一个测试(位于文件widget_spec.rb
中)间歇性失败。该测试创建Widget
的实例并调用get_cached_service
。我在控制台上看到Getting a cached service!
消息,随后是Do I already have one? false
,但我不看到Making a service!
消息。
此外,当我检查返回的traces
对象的Service
属性时,我发现了来自项目中其他测试的堆栈跟踪(例如{{1} },foo_spec.rb
等。
在一些不同的地方,我找到类似的代码:
bar_spec.rb
我发现其堆栈跟踪的其他测试可能像这样存根allow_any_instance_of(Widget)
.to receive(:make_service).and_return(whatever)
。但是看来这些测试之后并没有撤消存根,按照我的理解应该总是如此。
除了rspec中的错误以外,是否有其他原因可能导致存根在测试结束时不被重置?
答案 0 :(得分:0)
几乎可以肯定该存根已被清除,但是您已将伪造的实例缓存在get_cached_service
中。什么都不会清除@service
中的缓存值,并且RSpec(理所当然)不知道它。因此,如果测试调用make_service
,仅凭get_cached_service
就行了。您有几种选择:
get_cached_service
来代替make_service
或在其中存根答案 1 :(得分:0)
我意识到回答这个问题已经很晚了,但对于任何阅读此内容的人来说:
使用 git bisect 来确定是否存在导致失败的一致测试顺序,然后开始翻录代码,直到只剩下中断的部分。
我不记得 RSpec 出错的情况 - 几乎总是在某个地方有一个类变量没有被清除,或者有人手动使用类似 define_method
的类。有时它可能会发生在 gem 中。
确保在您的 spec_helper 中的每次测试后都清除所有内容 - 清除 Rails 缓存、清除 ActionMailer 交付、从 Timecop 冻结返回等。
任何与 RSpec 直接相关的东西在理论上都应该自我清除,因为它旨在集成到 RSpec 中,并且通常可能是最不可能的解释。