【问题标题】:Start ruby debugger if rspec test fails如果 rspec 测试失败,则启动 ruby​​ 调试器
【发布时间】:2013-04-30 00:26:07
【问题描述】:

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

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

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

但是,这种方法很麻烦,因为我首先等待测试失败,然后添加调试器行,修复问题,然后必须删除调试器行,而我希望它更像 gdb 那样工作能够在遇到异常时启动,而无需在您的代码库中添加 debugger 语句。

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

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

【问题讨论】:

    标签: ruby-on-rails rspec ruby-debug pry


    【解决方案1】:

    使用pry-rescue,它是普利茅斯的精神继承者:

    来自自述文件:

    如果您使用的是 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)>
    

    【讨论】:

    • 刚刚用最新的 zeus 和 pry-rescue 版本试了一下,不行
    【解决方案2】:

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

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

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

    【讨论】:

    • 有趣。不过,这不会捕获测试失败,对吗?
    【解决方案3】:

    我喜欢 @jon-rowe 的解决方案(不需要额外的 gem),只是稍作修改:我真的不像 RSpec::Expectations::ExpectationNotMetError 那样关心其他错误。

    config.around(:each) do |example|
      example.run.tap do |result|
        debugger if result.is_a?(RSpec::Expectations::ExpectationNotMetError)
      end
    end
    

    【讨论】:

      【解决方案4】:

      来自 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
      

      调试愉快!

      【讨论】:

        【解决方案5】:

        您需要在构造时捕获 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
        

        【讨论】:

        • 这看起来很有希望。我会尝试一下。谢谢,克利福德!
        【解决方案6】:

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

        HTH

        【讨论】:

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

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

        【讨论】:

        • pry-rescue(一个 pry 插件)远胜于hammertime,它将您置于异常的实际上下文中并让您遍历堆栈
        • 我去看看。感谢您的提示。
        猜你喜欢
        • 2020-03-16
        • 1970-01-01
        • 2023-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多