27

通常,当测试失败时,我会花很长时间试图找出导致它失败的原因。如果 RSpec 可以在测试失败时启动 Ruby 调试器会很有用,这样我就可以立即检查局部变量以深入了解原因。

我现在使用的解决方法如下所示:

# withing some test
debugger unless some_variable.nil?
expect(some_variable).to be_nil

但是,这种方法很麻烦,因为我首先等待测试失败,然后添加调试器行,修复问题,然后必须删除调试器行,而我希望它更像gdb能够在何时启动一个异常被击中,而不需要在你的代码库中添加debugger语句。

编辑:我试过普利茅斯。它对我来说还不够可靠。此外,开发历史似乎表明它不是一个得到很好支持的 gem,所以我宁愿不依赖它。

更新:我试过了pry-rescue,发现它很整洁。但是,我经常使用zeus,想知道是否有办法让它与pry-rescue.

4

7 回答 7

32

使用pry-rescue,它是 plymouth 的精神继承者:

从自述文件:

如果您使用的是 RSpec 或 respec,您可以使用rescue rspec 或rescue respec 在每次测试失败时打开一个pry session:

$ rescue rspec
From: /home/conrad/0/ruby/pry-rescue/examples/example_spec.rb @ line 9 :

     6:
     7: describe "Float" do
     8:   it "should be able to add" do
 =>  9:     (0.1 + 0.2).should == 0.3
    10:   end
    11: end

RSpec::Expectations::ExpectationNotMetError: expected: 0.3
     got: 0.30000000000000004 (using ==)
[1] pry(main)>
于 2013-04-30T15:07:32.960 回答
10

debugger如果不在块的范围内,您将无法(轻松)访问局部变量,但是RSpec为您提供了让您执行此操作的周围挂钩:

config.around(:each) do |example|
  result = example.run
  debugger if result.is_a?(Exception)
  puts "Debugging enabled"
end

然后,您此时可以访问@ivarssubject/let(:var)内容。

于 2013-04-30T06:59:44.150 回答
9

我喜欢@jon-rowe 的解决方案(不需要额外的宝石),只需稍加修改:我真的不关心其他错误,就像RSpec::Expectations::ExpectationNotMetError.

config.around(:each) do |example|
  example.run.tap do |result|
    debugger if result.is_a?(RSpec::Expectations::ExpectationNotMetError)
  end
end
于 2015-10-14T13:51:59.123 回答
3

从 Rspec 文档中:

RSpec 尝试提供有用的失败消息,但对于需要更具体信息的情况,您可以在示例中定义自己的消息。这适用于除运算符匹配器之外的任何匹配器。

我所做的是在该消息中调用 pry 。请参阅示例:

describe "failing" do
  context "test" do
    it "should start pry" do
      a = 3
      b = 1
      expect(a).to be == b, "#{require 'pry';binding.pry}"
    end
  end
end

调试愉快!

于 2021-02-11T08:07:21.543 回答
1

您需要在构造时捕获 ExpectationNotMatched 异常。在你的助手中包含以下代码,RSpec 将在构造异常时停止。这将是匹配器内部的几个级别,因此在调试器中,说“where”然后“up 5”或“up 6”,您将位于块的 instance_exec 中。调试器在我正在使用的版本中没有正确显示代码,但是您可以“向上”一次并在评估测试的同一上下文中运行代码,因此您可以检查实例变量(但不是局部变量,似乎)。

require 'debugger'
require 'rspec'

Debugger.start
class RSpec::Expectations::ExpectationNotMetError
  alias_method :firstaid_initialize, :initialize

  def initialize *args, &b
    send(:firstaid_initialize, *args, &b)
    puts "Stopped due to #{self.class}: #{message} at "+caller*"\n\t"
    debugger
    true # Exception thrown
  end
end

describe "RSpec" do
  it "should load use exceptions on should failure" do
    @foo = :bar    # An instance variable I can examine
    1.should == 2
  end
end
于 2013-04-30T01:56:34.947 回答
0

为此,您可以使用plymouth gem https://github.com/banister/plymouth。不过,它正在使用pry ,这是irb的(更好)替代品。

高温高压

于 2013-04-30T00:37:46.213 回答
-1

你可以试试锤子时间。每当引发异常时,它将停止并提示您进入交互式调试会话。

于 2013-04-30T03:55:53.410 回答