Много тестов - это хорошо, особенно если они еще и по делу.

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

Вдохновившись описанными получаемыми результатами:

, пробуем использовать ferrum вместо "медленных" selenium-webdrivers.

Чтобы получить относительно сопоставимые результаты, сделаем отдельный MR и сравним, что получится ДО и ПОСЛЕ.

Количество и качество тестов - одинаковое в данном случае.

Настройки

Как и описано, например вот здесь - Proper browser testing in Ruby on Rails (evil martians), настройки не представляют большой сложности.

Gemfile
...
+  gem 'cuprite'
-  gem 'webdrivers'
...

Конфигурация драйвера

Capybara.server = :puma, { Silent: true }
Capybara.register_driver :cuprite do |app|
  # FIXME: Two different keys for headless mode exist - one for Capybara (Cuprit) and one for Chromium - headless mode
  # [Chrome's headless mode](https://developer.chrome.com/articles/new-headless/#new-headless-in-selenium-webdriver)
  # It's impossible to set two keys with the same values - does not work

  if ENV['HEADLESS'].in?(%w[n 0 no false])
    browser_options = { 'no-sandbox': nil }
    headless = false
  else
    browser_options = { 'no-sandbox': nil, headless: 'new' }
    headless = 'new'
  end
  options = {
    browser_options:,
    window_size: [1600, 1200],
    inspector: true,
    headless:
    # js_errors: true
    # slowmo: 2,
    # process_timeout: 15
  }

  Capybara::Cuprite::Driver.new(app, options)
end

Capybara.save_path = DownloadHelpers::DOWNLOAD_PATH || './tmp/capybara'
# disable CSS transition and jQuery animation
Capybara.disable_animation = true
# Usually, especially when using Selenium, developers tend to increase the max wait time.
# With Cuprite, there is no need for that.
# We use a Capybara default value here explicitly.
# Capybara.default_max_wait_time = 2

# Normalize whitespaces when using `has_text?` and similar matchers,
# i.e., ignore newlines, trailing spaces, etc.
# That makes tests less dependent on slightly UI changes.
Capybara.default_normalize_ws = true

Capybara.javascript_driver = :cuprite


Запуск. Ошибки

Как и описано в упомянутых источниках и в ссылках внизу, часть тестов завершилась с ошибками. Примерное количество - 15-20% от общего числа.

Ошибки поделились на несколько категорий.

Самая распространенная

  • перестают работать одни из самых используемых методов - click_link (и его разновидности, например find('#id_blabla').click).

Причина оказалась простая и отчасти уважительная, драйвер "пытается" детально разобраться в структуре линка и, обнаруживая в нем что-то еще, выдает ошибку.

Это "что-то еще" оказалось используемыми css наподобие ::before, используемыми bootstrap и bulma для, например, смены background строки таблицы при наведении.

Везде, где применяются еще какие то дополнительные анимационные css, метод click_link не будет работать.

Пользуясь подсказкой ferrum (или cuprite), меняем click на trigger('click'), игнорируя предупреждение о том, что возможно нажимаем не совсем в той области, где планировали.

Обнаруживается вторая ошибка - метод trigger('click') на "нормальных" без css линках не работает.

Делаем два разных шага в cucumber для устранения данных ошибок, разбираемся, где линки с css, а где нет - и в результате большая часть (примерно 95%) тестов начинает работать с новым драйвером.

Ошибка два

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

Устанавливаемые значения - все срабатывает, а вот возвращается всегда nil.

В описании Ferrum JavaScript находим, что для выполнения JS и выполнения с возвратом значения используются разные методы (evaluate/execute).

Возможно при реализации Cuprite этот нюанс не был учтен, меняем метод там, где необходимы значения и тесты начинают работать.

Ошибка три

Вызвана тем, что headless и headful режим работает различно. Проявляется это просто - в режиме headful тест выполняется, в режиме headless - падает с ошибкой, связанной с тем, что не отрабатывает стандартная функция onchange: 'this.form.submit()'.

Руководствуясь документом от Google Chrome’s Headless mode меняем headless mode на новую.

Здесь возникает еще один не очень понятный момент, связанный с тем, что mode определяется в ДВУХ местах. В настройках параметров драйвера и в настройках параметров браузера драйвера. В итоге пока оставляем так, как приведено выше в конфигурации.

И после этого все тесты начинают работать.

Результаты

Это не benchmark, это просто вывод времени выполнения каждого теста для одной и той же группы тестов, на одной и той же локальной машине.

Исходные данные:

Количественные показатели тестов

  • Cucumber 70 scenarios (550 steps)

  • RSpec 346 examples

Характеристики компьютера

  • Linux version 5.15.0-76-generic (buildd@lcy02-amd64-028)

  • Intel(R) Xeon(R) CPU E5-2697A v4 @ 2.60GHz

  • 16373244 K total memory

Измерения скорости выполнения тестов

Измерения проводились исключительно с целью примерного сравнения без применения каких либо специализированных инструментов.

Для "усреднения" использовалась command-line benchmarking tool

cuprite

  • RSpec
    (Migrate_to_ferrum) hyperfine --runs 5 'bundle exec rspec'
    Benchmark 1: bundle exec rspec
    Time (mean ± σ): 127.121 s ± 0.743 s [User: 90.705 s, System: 11.023 s]
    Range (min … max): 126.002 s … 127.780 s 5 runs

  • Cucumber
    (Migrate_to_ferrum) hyperfine --runs 5 'bundle exec cucumber'
    Benchmark 1: bundle exec cucumber
    Time (mean ± σ): 165.294 s ± 1.112 s [User: 112.951 s, System: 20.299 s]
    Range (min … max): 164.166 s … 166.902 s 5 runs

selenium-webdrivers

  • Rspec
    (master) hyperfine --runs 5 'bundle exec rspec'
    Benchmark 1: bundle exec rspec
    Time (mean ± σ): 121.184 s ± 0.684 s [User: 83.846 s, System: 8.371 s]
    Range (min … max): 120.355 s … 122.083 s 5 runs

  • Cucumber
    (master) hyperfine --runs 5 'bundle exec cucumber'
    Benchmark 1: bundle exec cucumber
    Time (mean ± σ): 156.351 s ± 0.834 s [User: 103.068 s, System: 22.487 s]
    Range (min … max): 155.059 s … 157.337 s 5 runs

Сравнительная таблица:

Driver

RSpec

Cucumber

Selenium

120.355 s … 122.083 s

155.059 s … 157.337 s

Cuprite

126.002 s … 127.780 s

164.166 s … 166.902 s

Легенда:

  • Selenium - тесты с использованием драйвера selenium-webdrivers и Chrome

  • Cuprite - тесты с использованием драйвера cuprite и Chrome

Результаты, мягко говоря, неожиданные.

Близкие результаты Rspec определяются тем, что шагов с capybara там немного.

А вот для cucumber - половина шагов использует capybara.

Еще немного о странностях

Дальнейшее изучение проблемы с быстродействием драйвера ferrum привело к совершенно неожиданным результатам.

Одни и те же тесты в одном и том же окружении при смене версии браузера ведут себя совершенно по разному.

Для примера:

Версия браузера 108.0.5359.98 (Официальная сборка), (64 бит) - у коллеги на машине, linux

  • Падает один тест, который до этого не падал. Ошибка связана с тем, что не работает функция onclick. Возможно в этой версии браузера headless еще "старой" конструкции.

Версия 114.0.5735.198

  • все тесты выполняются без ошибок.

Google Chrome 115.0.5790.102 - последняя на текущий момент.

  • начали падать ДВА теста. Стабильно. На разных (двух) машинах, с MacOS и Linux. При этом попытка "разобраться", в чем там дело, завершилась несколько неудачно. Эти же тесты, но запущенные по ОДНОМУ - не падают вообще.

Предварительные выводы

Плюсы:

  • Возможность использования дополнительных инструментов для позиционирования, заполнения, анализа страницы

  • Отладка - возможность debug с текущей страницей - это просто замечательно. Подробности см. (https://github.com/rubycdp/cuprite#debugging)

  • Большое кол-во дополнительных полезных функций, как то ожидание ответа по AJAX, поиск по css и т.д. Справедливо будет отметить, что все эти "дополнительные" методы относятся к драйверу ferrum, а не к cuprite. Примерно так же можно использовать аналогичные методы selenuim, так что этот плюс можно считать весьма условным.

Минусы:

  • Поведение с разными версиями браузера ???

  • Быстродействие ???

Пока полученные результаты не позволяют сделать вывод о целесообразности замены selenium-webdrivers на ferrum.

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

Возможно проблема в том, что именно тестируется с помощью capybara.

Используемые нами тесты - это стандартные интеграционные тесты и не включают тестирование интерфейса как такового.

Активно используется поиск и заполнение полей, чек-боксов, выбор из списков, управление JS компонентами типа редактор tinyMCE и т.д.

Все тестируемые компоненты форм требуют авторизации, здесь используется стандартный helper от devise и в случае selenium-webdrivers, и в случае ferrum.

Вполне возможно, что быстродействие можно будет увеличить за счет использования предоставляемого механизма управления сессиями и отказа от использования sign-in.

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

А проводить тестирование под условным "суперпользователем" как то не очень логично, особенно, если тестируются ограничения этого доступа.

Полученные результаты не позволяют сделать вывод о целесообразности замены используемого драйвера selenium-webdrivers на ferrum по состоянию разработки на текущий момент.

  • ferrum (0.13)

  • cuprite (0.14.3)

  • Rails 7.0.6

Используемые источники

Комментарии (0)