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

时间:2019-04-09 23:31:44

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

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

在一些不同的地方,我找到类似的代码:

bar_spec.rb

我发现其堆栈跟踪的其他测试可能像这样存根allow_any_instance_of(Widget) .to receive(:make_service).and_return(whatever) 。但是看来这些测试之后并没有撤消存根,按照我的理解应该总是如此。

除了rspec中的错误以外,是否有其他原因可能导致存根在测试结束时不被重置?

2 个答案:

答案 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 中,并且通常可能是最不可能的解释。