RSpec 存根显然在测试后未清理

  • 本文关键字:测试 存根 RSpec ruby rspec
  • 更新时间 :
  • 英文 :


我一直在努力诊断仅在我的主分支上发生的测试失败。 以下是简化形式的相关代码。

有一项服务:

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!消息。

此外,当我检查返回的Service对象的traces属性时,我发现源自项目中其他测试的堆栈跟踪(例如。foo_spec.rbbar_spec.rb等)。

在几个不同的地方,我找到了这样的代码:

allow_any_instance_of(Widget)
.to receive(:make_service).and_return(whatever)

我发现其堆栈跟踪的其他测试可能会像这样make_service。 但似乎在这些测试之后,存根并没有被撤消,根据我的理解,这应该总是发生。

除了 rspec 中的错误之外,是否有任何原因可能导致存根在测试结束时无法重置?

存根几乎肯定已被清除,但您已将假实例缓存在get_cached_service中。没有什么可以清除@service中的缓存值,RSpec(理所当然地)不知道它。因此,如果测试调用get_cached_service,则存根make_service是不够的。您有以下几种选择:

  • 始终存根get_cached_service而不是make_service,或者除了
  • 提供一种方法来清除每次测试后调用的缓存值。
  • 使缓存以某种方式可配置,或围绕实际实现的包装器,以便缓存不会在测试代码中发生。

我意识到这回答已经很晚了,但对于任何读到这篇文章的人来说:

使用 rspec 平分来确定是否存在导致失败的一致测试顺序,然后开始撕掉代码,直到只剩下中断的位。

我不记得 RSpec 有故障的情况 - 几乎总是,某处有一个类变量未被清除,或者有人正在手动玩一个类,比如define_method.偶尔它可能发生在宝石中。

确保在spec_helper的每次测试后清除所有内容 - 清除Rails缓存,清除ActionMailer交付,从Timecop冻结返回等。

任何与RSpec直接相关的内容都应该在理论上清除自己,因为它旨在集成到RSpec中,并且可能是一般情况下最不可能的解释。

最新更新