【问题标题】:How to test whether any exception was rescued?如何测试是否有任何异常被抢救?
【发布时间】:2017-07-12 17:52:27
【问题描述】:

有没有办法查明在某些代码的执行过程中是否引发并挽救了任何异常?

最好在使用 ActiveSupport::TestCase 而不是 RSpec 编写的测试中

是否有任何全局 ruby​​ 异常堆栈之类的东西,我可以检查一下?

【问题讨论】:

  • 设置你的fixture,让它引发错误并验证错误没有泄漏。
  • @ndn 如何从夹具中引发错误?顺便说一句,错误不在数据中,而在代码本身..
  • 我所说的fixture不是指rail的fixture,我指的是运行测试的前提条件/环境。只需确保在设置中完成了引发错误所需的一切。
  • @ndn 啊,我明白了。只是我在另一个我不想要异常的测试用例中遇到了这个问题,但它们显然还是发生了,被默默地救了出来,并导致我的测试用例失败,因为一些代码没有在点以下执行引发异常的地方。因此,如果有任何全局 ruby​​ 异常堆栈或者我在测试中可以检查的东西是否为空,我会很高兴。
  • “另一个我不想要异常的测试用例,但它们显然还是发生了” - 是什么导致了失败?您要么为不应该关心的测试设置了错误流,要么实现本身有问题。

标签: ruby-on-rails ruby exception testing testcase


【解决方案1】:

如果你想成为一个怪物,你可以自己检测错误:

class StandardError
  @@called = false

  def initialize
    @@called = true
    super
  end

  def self.called
    @@called
  end
end

#test it out like so:

def raise_arg_error
  raise ArgumentError
rescue
end

puts ArgumentError.called #false
raise_arg_error
puts ArgumentError.called #true

非常适合临时健全性检查。生产代码太糟糕了。

【讨论】:

  • 有趣的方法!也许我只能在测试代码中做到这一点..(虽然根据测试方法最佳实践不确定这是否明智..)。为什么对生产代码来说这很糟糕?额外的属性不会改变 StandardError 自然的工作方式,所以它不一定会打破其他程序员的期望..
  • @Magne 对于新开发人员进入您的项目并进行发现来说,这是一个不错的小 wtf。然后他将利用它来实现实际的生产功能。
  • StandardError.new 还将 @@called 设置为 true,即使没有引发异常。
  • @fylooi 好吧,如果它没有破坏 StandardError 自然工作的预期方式,那么发现它就不是一件好事了..?如果另一个程序员使用它来实现实际的生产功能,它可能会变得非常糟糕,我同意。当然,猴子修补可能会产生潜在的危险优先级。但是很难防范其他程序员的愚蠢行为......除了可能记录猴子补丁并建议不要在生产代码中构建它(或进一步的猴子补丁)......
  • 出现错误。开发人员无法找出它的根本原因。老板在开发人员的脖子上喘着粗气,并在最后期限上喋喋不休。开发人员决定采用生产解决方法来监控和修复错误的副作用。嘿,以前有人这样做过,我只是复制代码! (顺便说一句,我见过有人这样做)
【解决方案2】:

正如 cmets 中所阐明的,OP 需要它来进行调试,而不是用它编写测试。


Kernel#set_trace_func 允许您拦截低级别事件,例如引发错误:

set_trace_func(proc do |event, *_|
  puts 'Raised!' if event == 'raise'
end)

raise 'Oh, no!' rescue :foo

您可以在尝试调试的代码之前运行#set_trace_func。如果没有引发异常,但 hook 注册了引发 - 有人救了它。


这可能会产生一些噪音,具体取决于您正在执行的操作。幸运的是,您可以按文件和行对其进行过滤:

set_trace_func(proc do |event, file, line, *_|
  if event == 'raise' && file == 'test.rb' && line == 42
    puts "Raised on #{file}:#{line}!"
  end
end)

它甚至为您提供绑定,因此您可以下拉调试器:

require 'irb'

set_trace_func(proc do |event, *_, error_binding, _|
  error_binding.irb if event == 'raise'
end)

def foo
  bar = 42
  raise 'Oh, no!' rescue :baz
end

foo

# Opens an irb
# > bar # => 42

【讨论】:

  • 谢谢!这太棒了!
猜你喜欢
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-16
相关资源
最近更新 更多