Запустите отладчик 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
.
Ответы
Ответ 1
Используйте pry-rescue, это духовный преемник Плимута:
Из Readme:
Если вы используете RSpec или respec, вы можете открыть сеанс pry при каждом провале теста, используя аварийный rspec или rescue 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)>
Ответ 2
Вы не получите доступ к локальным переменным (легко) без debugger
, находящимся в области блока, однако RSpec
предоставляет вам вокруг крючков, которые позволяют это сделать:
config.around(:each) do |example|
result = example.run
debugger if result.is_a?(Exception)
puts "Debugging enabled"
end
После этого у вас есть доступ к содержимому @ivars
и subject
/let(:var)
.
Ответ 3
Мне нравится решение @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
Ответ 4
Вам нужно поймать исключение ExpectationNotMatched во время его создания. Включите следующий код в своих помощниках где-нибудь, и RSpec остановится, когда будет построено исключение. Это будет несколько уровней в глубине внутри, поэтому в отладчике скажите "where", затем "вверх 5" или "вверх 6", и вы попадете в экземпляр экземпляра вашего блока. Отладчик не показывает код правильно в используемой вами версии, но вы можете "подняться" еще раз и перейти к запуску кода в том же контексте, где оценивается ваш тест, поэтому вы можете проверить переменные экземпляра (но а не локальные переменные).
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
Ответ 5
Вы можете использовать plymouth gem https://github.com/banister/plymouth. Он использует pry, хотя (лучше) альтернативу irb.
НТН
Ответ 6
Вы можете попробовать hammertime. Он остановится и предложит пригласить вас в интерактивную сессию отладки всякий раз, когда возникает исключение.