Запустите отладчик ruby, если тест rspec не прошел

Часто, когда тест терпит неудачу, я трачу некоторое время, пытаясь выяснить, что вызвало его неудачу. Было бы полезно, если бы RSpec мог запускать отладчик Ruby при сбое теста, чтобы я мог немедленно проверить локальные переменные, чтобы выяснить причину.

Обходной путь, который я сейчас использую, выглядит примерно так:

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

Однако этот подход громоздкий, потому что я сначала жду, когда тест завершится ошибкой, затем добавляю строку отладчика, исправляю проблему, а затем должен удалить строку отладчика, тогда как я хочу, чтобы он работал больше как gdb, у которого есть возможность запуска при попадании исключения, не требуя добавления в кодовую базу операторов debugger.

Изменить: я пробовал Плимут. Он не работал достаточно надежно для меня. Кроме того, история разработки, похоже, указывает на то, что это не очень хорошо поддерживаемый камень, поэтому я бы не стал на него полагаться.

Обновление: я опробовал pry-rescue и считаю, что это удобно. Тем не менее, я часто использую zeus, и мне было интересно, есть ли способ заставить его работать с pry-rescue.


person Vighnesh    schedule 30.04.2013    source источник


Ответы (7)


Используйте pry-rescue, это духовный преемник plymouth:

Из Ридми:

Если вы используете RSpec или respec, вы можете открывать сеанс проверки при каждом сбое теста, используя Respec rspec или Respec Respec:

$ 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)>
person horseyguy    schedule 30.04.2013
comment
Только что попробовал с новейшей версией zeus и pry-rescue, не работает - person 23tux; 04.02.2015

Вы не получите доступ к локальным переменным (легко), если debugger не находится в области действия блока, однако RSpec предоставляет вам хуки вокруг, которые позволяют вам сделать это:

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

Теперь у вас есть доступ к содержимому @ivars и subject / let(:var).

person Jon Rowe    schedule 30.04.2013
comment
Интересно. Тем не менее, это не будет отлавливать сбои тестов, не так ли? - person Vighnesh; 01.05.2013

Мне нравится решение @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
person stringsn88keys    schedule 14.10.2015

Вам нужно поймать исключение ExpectationNotMatched во время его создания. Включите следующий код в свои помощники где-нибудь, и RSpec остановится при создании исключения. Это будет несколько уровней внутри сопоставителей, поэтому в отладчике скажите «где», затем «вверх 5» или «вверх 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
person cliffordheath    schedule 30.04.2013
comment
Это выглядит очень многообещающе. Я попробую. Спасибо, Клиффорд! - person Vighnesh; 01.05.2013

Из документации 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

Удачной отладки!

person Claudiu    schedule 11.02.2021

Вы можете использовать гем plymouth https://github.com/banister/plymouth для этого. Однако он использует pry, (лучшую) альтернативу irb.

ХТН

person a.s.t.r.o    schedule 30.04.2013
comment
Я пробовал Плимут. Он не работал достаточно надежно для меня. Кроме того, история разработки, похоже, указывает на то, что это не очень хорошо поддерживаемый камень, поэтому я бы не стал на него полагаться. - person Vighnesh; 30.04.2013

Вы можете попробовать hammertime. Он остановится и предложит перейти к интерактивному сеансу отладки всякий раз, когда возникнет исключение.

person davogones    schedule 30.04.2013
comment
pry-rescue (плагин pry) намного лучше хаммертайма, он бросает вас в настоящую контекст исключения и позволяет пройтись по стеку - person horseyguy; 30.04.2013
comment
Я проверю это. Спасибо за совет. - person Vighnesh; 01.05.2013