【问题标题】:Writing RSpec Test for Rescued Exception为已获救的异常编写 RSpec 测试
【发布时间】:2019-10-29 20:54:50
【问题描述】:

我有这样的代码:

module Empiric
  module_function

  def gem_version(name)
    Gem.loaded_specs[name].version
  rescue NoMethodError
    raise NoMethodError, "No gem loaded for #{name}"
  end
end

这旨在查找已加载的 gem 并在找到 gem 时给出版本。例如,在我的项目中,Capybara gem 将不存在,所以这是可行的:

Empiric.gem_version("capybara")

当我说它“有效”时,我的意思是它引发了适当的异常。我正在尝试为此创建一个 RSpec 测试,我想出了这个:

it "indicates if a dependent gem is not found" do
  expect {
    Empiric.get_version("capybara")
  }.to raise_error NoMethodError
end

测试通过了……但是,测试覆盖率表明我的raise 部分没有被覆盖。

然而,如果我将上面的测试改为.not_to raise_error NoMethodError,测试就会失败。正如它应该。请注意,我将其更改为“not_to”而不是“to”。所以这向我表明,测试实际上是在识别产生了错误。

这是否与我专门拯救错误的事实有关?因为rescue 行显示它已包含在测试覆盖率报告中,但raise 语句没有,即使我已经验证它确实发生了。

在尝试回答我自己的问题时,我确实遇到了这个问题 (How to write down the rspec to test rescue block.?),但该解决方案似乎对我根本不起作用。我还查看了这个 (How do I test the rescue block of a method with rspec mocks 3.3),它对我的​​帮助也很少。对于这个 (Rspec: testing a rescue) 和这个 (Using RSpec how can I test the results of a rescue exception block) 和这个 (Rspec: Test rescue block) 也是如此。

为了清楚起见,我不是在 Rails 上下文中操作。这是我正在编写的独立 gem。

【问题讨论】:

  • 在第一步中,我将使用expect { ... }.to raise_error NoMethodError, "No gem loaded for capybara" 检查异常附加了哪些消息。也许这是报道记者的一个错误?
  • 有趣。当我尝试从 rspec 得到这个时:expected NoMethodError with "No gem loaded for capybara", got #<NoMethodError: undefined method get_version' for Empiric:Module>`。这绝对是奇怪的,因为我可以在测试之外毫无问题地调用该方法并且不添加异常消息,所以我没有收到关于根本找不到该方法的错误。我使用的覆盖工具是 SimpleCov。
  • 嘿,这是get_version vs gem_version ;)
  • 拯救 NoMethodError 并不是一个好主意,因为它是一个很好的掩盖错误的方法。相反,您应该使用 Hash#fetch 和救援 KeyError 或安全运算符 .&
  • 使用 Gem.loaded_specs.fetch(name).versionrescue KeyError 或安全运算符 Gem.loaded_specs.fetch(name).&version 并检查 nil。

标签: ruby rspec


【解决方案1】:

好的,所以这里的答案非常简单(感谢@katafrakt 指出)。我会在这里给出一个答案,因为我觉得这很有趣。

问题出在我的测试中:

it "indicates if a dependent gem is not found" do
  expect {
    Empiric.get_version("capybara")
  }.to raise_error NoMethodError
end

注意我打电话给get_version,而不是gem_version。但是……那为什么测试没有表明这一点呢?至少会失败,这是我所预料的。

我发现问题的唯一方法是添加异常提供的消息。也就是说:

...
.to raise_error NoMethodError, "No gem loaded for capybara."

然后执行告诉我没有定义get_version 方法。具体来说,我得到了这个:

expected NoMethodError with "No gem loaded for capybara",
got #<NoMethodError: undefined method `get_version' for Empiric:Module>

显然,修复测试以调用正确的方法就可以了。但不太清楚的是,为什么当我明显调用不正确的方法时测试最初显示为通过。不仅是一种不正确的方法,而且是一种不存在的方法。我的代码中根本没有 get_version 方法。

但请注意,我首先要抢救“NoMethodError”。所以也许这就是这种情况?也许get_version 本身是一个 NoMethodError 的事实被测试的行为所吞噬?只有当我为 my 异常输入特定消息时,才会强制 RSpec 意识到 actual NoMethodError - 带有不同的消息 - 正在发生。

我很想删除这个问题,因为我显然犯了一个愚蠢的错误。但我觉得这个错误的背景可能对其他人来说很有趣。如果版主不同意并认为应该将其删除,请不要担心。否则,我的愚蠢会被所有人看到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    相关资源
    最近更新 更多