Как избежать сбоя ожидающих запросов после отката базы данных в интеграционных тестах?

#ruby-on-rails #ruby #capybara #minitest

#ruby-on-rails #ruby #capybara #minitest

Вопрос:

У нас периодически возникает проблема, и я хотел бы узнать, есть ли у кого-нибудь здесь представление о том, как мы можем ее решить. Мы проводим наши интеграционные тесты с Minitest Capybara и драйвером Chrome headless.

Проблема возникает, когда тест завершен, и база данных получает ОТКАТ. В фоновом режиме все еще могут выполняться некоторые незавершенные запросы, и могут возникать сбои (например, RecordNotFound), если они пытаются получить доступ к недоступной информации базы данных.

Такого рода проблемы чаще всего возникают из-за запросов AJAX, и для этого мы уже используем помощник wait_for_ajax (который мы разработали сами), чтобы дождаться, пока браузер завершит выполнение своих запросов.

Нерешенная проблема возникает с <img> HTML-тегами, потому что браузер все еще может пытаться асинхронно загружать изображения, даже если тесты завершены.

Вот пример кода, который вызывал бы проблему почти все время:

 test 'image popup should contain some class' do
  upload_some_images # Uploads images
  visit '/list_of_images' # Some page with list of images, you can click on the image and it opens it in a popup

  find('.image-popup-open-button').click # Open image in a popup window
  assert_selector '.some-class-must-be-present'
end
  

Это простой тест, однако в нашем случае он всегда завершается сбоем с ActiveRecord::RecordNotFound blob id=xxx ошибкой.

  • При открытии всплывающего окна в DOM добавляется <img src='/files/123' /> . Затем браузер запрашивает это и перенаправляется на URL-адрес представления ActiveRecord.
  • Интеграционный тест довольно прост и проверяет, присутствует ли какой-либо класс, после чего тест завершается и выполняется ОТКАТ базы данных.
  • Запрос на /files/123 все еще выполняется, который затем пытается загрузить большой двоичный объект (запись базы данных), который больше не существует, и приводит к неожиданному сбою теста.

У кого-нибудь когда-либо была такая проблема, если да, то как вам удалось ее избежать?

Мы используем Ruby 2.5.0, Rails 5.2.2, Capybara 3.0.3

Спасибо

Комментарии:

1. Какую версию Rails вы используете? Используете ли вы средство очистки базы данных? Какая версия Capybara? Вы переопределили поведение сброса сеанса Capybara по умолчанию? Вы разрешаете Capybara управлять запуском тестируемого приложения или вы отключили это? Текущая настройка Capybaras по умолчанию должна ожидать завершения всех запросов при сбросе сеанса, если только вы не отключили это, пытаясь выполнить пользовательские действия.

2. Хорошо — Вы используете Rails 5.2.2, поэтому вам не следует использовать database_cleaner, поскольку Rails обрабатывает это из Rails 5.1 — Вы пишете системные тесты Rails? Если да, то у вас случайно не было записанных teardown блоков, которые вы забыли вызвать super ? Если это так, это предотвратит вызов Capybaras reset_sessions! , где Capybara ожидает завершения всех текущих запросов, прежде чем двигаться дальше. Если вы не используете системные тесты, есть ли у вас собственный teardown блок, который вызывает Capybara.reset_sessions! в конце теста? Кроме того, Capybara 3.0.3 в настоящее время устарела

3. Привет @ ThomasWalpole, я обновил вопрос версиями gem, спасибо, что напомнили мне поставить их. Мы не используем какой-либо драгоценный камень для очистки базы данных, мы используем rails-приспособления. Для поведения сеанса мы внедрили что-то вроде этой документации , хотя я заметил, что мы переопределили def after_teardown и не def teardown , не уверен, что это сильно изменится. Ваш вопрос «разрешить Capybara управлять запущенным тестируемым приложением», я не уверен, что вы имеете в виду, извините.

4. after_teardown vs teardown будет иметь огромное значение, если БД откатывается во время teardown Capybara.reset_sessions! необходимо вызвать до отката БД (я не помню, на каком этапе Rails откатывается в интеграционных тестах — но системные тесты специально вызывают reset_sessions из teardown, а не after_teardown, поэтому я предполагаю, что это должно быть в teardown — попробуйте и посмотрите) Все это предполагает, что вы разрешаете Capybara запускать приложение (вы не установили Capybara.run_server = false, а затем установили app_host для другого экземпляра приложения, для которого вы управляете запуском)

5. Что ж! @ThomasWalpole Ты мой мужчина! Это действительно был teardown vs after_teardown . Rails, скорее всего, выполняет откат в, after_teardown потому что после перемещения super вызова после Capybara.reset_sessions! это сработало. Спасибо, что указали мне правильные направления, мои знания о Capybara все еще ограничены, поэтому я не смог точно определить, когда / где что-то происходит.

Ответ №1:

Предполагая, что Capybara управляет запуском тестируемого приложения, Capybara.reset_sessions! будет ждать завершения всех открытых запросов. Это должно произойти до того, как база данных будет откатана. При использовании системных тестов Rails это будет обрабатываться в teardown блоке до тех пор, пока вы вызываете super из любых teardown определенных вами блоков. Если вы не используете системные тесты и просто основываете свои тесты на IntegerationTests, вам нужно определить teardown блок, который вызывает Capybara.reset_sessions! , чтобы он ожидал завершения всех запросов, прежде чем Rails откатит базу данных.

Ответ №2:

Оказалось, что мы реализовали Capybara таким образом:

 def after_teardown
  super
  Capybara.reset_sessions!
  Capybara.use_default_driver
end
  

но Rails выполняет откат базы данных при super вызове after_teardown . Таким образом, база данных была откатана до того, как Capybara ожидает завершения сеанса.

Перемещение super after Capybara.reset_sessions! сделало свое дело (также имеет смысл вместо этого поместить его внутрь def teardown , что, скорее всего, мы и сделаем).

Спасибо @ThomasWalpole за то, что указал мне правильное направление.