Есть ли хороший способ отлаживать ошибки, зависящие от порядка в RSpec (RSpec2)?

Слишком часто люди пишут тесты, которые не очищаются после себя, когда они воюют с состоянием. Часто это не имеет значения, поскольку объекты, как правило, срываются и воссоздаются для большинства тестов, но есть некоторые неудачные случаи, когда глобальное состояние объектов сохраняется и для всего тестового прогона, и когда вы запускаете тесты, которые зависят и изменяют что глобальное состояние в определенном порядке терпит неудачу.

Эти тесты и, возможно, реализации должны быть исправлены, но это боль, чтобы попытаться выяснить, что является причиной сбоя, когда тесты, которые влияют друг на друга, могут быть не единственными вещами в полном комплекте тестов. Это особенно сложно, когда изначально не ясно, что сбои зависят от порядка и могут прерываться с перерывами или на одной машине, но не в другой. Например:

rspec test1_spec.rb test2_spec.rb # failures in test2
rspec test2_spec.rb test1_spec.rb # no failures

В RSpec 1 были некоторые параметры (--reverse, --loadby) для заказа тестовых прогонов, но они исчезли в RSpec 2 и были минимально полезны при отладке этих проблем.

Я не уверен в том, что по умолчанию используется RSpec 1 или RSpec 2, но один специально разработанный тестовый набор, который я использовал в прошлом, произвольно заказывал тесты при каждом запуске, чтобы эти сбои освещались быстрее. На тестовом выходе семя, которое использовалось для определения порядка, было напечатано с результатами, чтобы было легко воспроизвести сбои, даже если вам пришлось выполнить некоторую работу, чтобы сузить отдельные тесты в пакете, который их вызывал. Затем были варианты, которые позволяли вам запускать и останавливаться в любом тестовом файле в порядке, что позволило вам легко выполнить двоичный поиск, чтобы найти тесты проблем.

Я не нашел таких утилит в RSpec, поэтому я спрашиваю здесь: Какими хорошими способами люди обнаружили для отладки этих типов ошибок, зависящих от порядка?

Ответ 1

Нашел свой собственный вопрос через 4 года, и теперь у rspec есть флаг --order, который позволяет вам установить произвольный порядок, и если вы получаете ошибки, зависящие от порядка, выполните воспроизведение с --seed 123, где семя распечатывается на каждой спецификации работать.

https://www.relishapp.com/rspec/rspec-core/v/2-13/docs/command-line/order-new-in-rspec-core-2-8

Ответ 2

Теперь существует флаг --bisect, который найдет минимальный набор тестов для воспроизведения, чтобы воспроизвести сбой. Попробуйте:

$ rspec --bisect=verbose

Также может быть полезно использовать с ним флаг --fail-fast.

Ответ 3

Я бы не сказал, что у меня есть хороший ответ, и мне бы хотелось, чтобы здесь были лучшие решения, чем у меня. Тем не менее...

Единственная реальная технология, которую я имею для отладки этих проблем, - это добавить глобальный (через spec_helper) крючок для печати некоторого аспекта состояния базы данных (моего обычного виновника) до и после каждого теста (чтобы проверить, не волнует я или нет). Недавний пример заключался в добавлении чего-то подобного к моему spec_helper.rb.

Spec::Runner.configure do |config|
  config.before(:each) do
    $label_count = Label.count
  end

  config.after(:each) do
    label_diff = Label.count - $label_count
    $label_count = Label.count
    puts "#{self.class.description} #{description} altered label count by #{label_diff}" if label_diff != 0
  end
end

Ответ 4

У нас есть один тест в нашей настройке непрерывной интеграции, который объединяет каталог spec/приложения Rails и запускает каждый из них друг против друга.

Занимает много времени, но мы нашли 5 или 6 зависимостей таким образом.

Ответ 5

Вот несколько быстрых грязных script, которые я написал для отладки зависимых от заказа сбоев - https://gist.github.com/biomancer/ddf59bd841dbf0c448f7

Он состоит из двух частей.

Первый предназначен для запуска rspec несколько раз с различными результатами семян и дампов в rspec_[ok|fail]_[seed].txt файлы в текущем каталоге для сбора статистики.

Вторая часть выполняет итерацию по всем этим файлам, извлекает имена тестовых групп и анализирует их позицию в затронутом тесте, чтобы сделать предположения относительно зависимостей и формирует группы "риска" - безопасные, небезопасные и т.д. Выход script объясняет другие детали и групповые значения.

Этот script будет корректно работать только для простых зависимостей и только если поврежденный тест терпит неудачу для некоторых семян и пропусков для других, но я думаю, что он все же лучше, чем ничего. В моем случае это была сложная зависимость, когда эффект мог быть отменен другим тестом, но этот script помог мне получить указания после многократного выполнения его аналитической части на разных наборах дампов, в частности только на неудачных (я просто переехал "ok 'выгружается из текущего каталога).

Ответ 6

Скорее всего, какое-то состояние сохраняется между тестами, поэтому убедитесь, что ваша база данных и любые другие хранилища данных (включая класс var и globals) reset после каждого теста. database_cleaner может помочь.