Разделы портала

Онлайн-тренинги

.
Как оценить покрытие автоматизации
21.05.2021 00:00

Автор: Алан Ричардсон (Alan Richardson)
Оригинал статьи
Перевод: Ольга Алифанова

Краткое содержание: покрытие требует моделирования. Мы можем организовать код так, чтобы его можно было оценить на основании ментальной модели, и некоторые из моделей исполнимы. Другие модели мы сравниваем с результатами прогона тестов.

Мне задали ряд вопросов: как задокументировать, что делает и что покрывает автотест, не затрачивая кучу времени и сил? Как узнать, что не покрыто автоматизацией?

Вспомогательное видео: ссылка на YouTube

Покрытие

Любая оценка покрытия включает сравнение с какой-либо моделью, какой-либо реализацией.

Проводя код-ревью, смотря на код и разбираясь, что покрыто, мы обычно основываемся на ментальной модели – то есть на своих ожиданиях, что должно быть покрыто. Затем в ходе разбора кода мы сравниваем его со своей моделью.

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

Следовательно, работа идет на нескольких уровнях.

Мы сравниваем детали метода @Test с моделью, чтобы оценить покрытие реализованной процедуры и использованных утверждений.

Мы оцениваем результат в терминах структуры объекта и наименований, чтобы оценить покрытие системы в целом.

Работая над Agile-проектами, разбивающими процесс поставки на сторис, мы дробим наши ревью на кусочки размером со строи, и используем коммиты контроля версий, чтобы ограничить объем своих оценок объемом сторис.

Как задокументировать, что делает автотест?

  • Имя автотеста может с этим помочь:
    • Напишите предложение через camelCase, чтобы описать цель теста.
    • Если вы не можете выразить цель теста через его имя – возможно, вы стараетесь протестировать чересчур многое.
    • Создайте уровни абстракции, чтобы тест-код был легко читабелен в ходе детального ревью.
    • Все утверждения должны находиться в тест-коде, а не прятаться на уровнях абстракции – это сделает покрытие условий очевидным.
    • Сделайте важные данные видимыми, прячьте неважные данные на уровнях абстракции – к примеру, классы генерации тестовых данных.

Как организовать код, чтобы упростить оценку покрытия?

  • Структура тестов очень важна
    • Имя тест-класса
    • Структура объекта предоставляет организационную иерархию

Как мы узнаем, что не покрыто?

В ходе процесса "картирования".

Нам нужна модель того, что нужно покрыть, а также способ наложить тест на "покрытое".

Кастомизация

Этот процесс можно кастомизировать.

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

Карты также могут получиться в результате запуска тест-кода.

Например:

  • Если вы тестируете API, вы можете перехватить весь трафик и сравнить его с моделью API – были ли вызваны все конечные точки? Использованы ли все параметры? Глаголы? И т. д.
    • Раньше я использовал для этого закодированные прокси и обработанные HAR-файлы.
  • Если вы тестируете интерфейс, то можно перехватить трафик и сравнить его с картой сайта – посетили ли вы все страницы? И так далее.

Инструментарий

Некоторые команды используют Cucumber и аналогичные DSL-инструменты. Непокрытые области – это те, которые еще не внедрены, поэтому Cucumber подсвечивает их, но тесты все равно "проходят".

Это происходит при использовании Gherkin в качестве модели – она становится выполнимой после интерпретации Cucumber, а картирование достигается, когда код создан и успешно выполнен.

Примечание: можно заметить, что если называть это BDD или использовать BDD в описании такого подхода – то это неправильное применение инструмента. Однако если вы просто хотите использовать инструмент моделирования на основе DSL, который может подсвечивать покрытие на DSL-уровне, то этот подход может вам пригодиться.

Есть риск увлечься и моделировать в Cucumber все подряд, что может затормозить ваш проект.

Cucumber очень полезен для моделирования высокоуровневых процессов в форме DSL, управляемого через данные через таблицу важных данных. Если вы положите в эту таблицу все свои данные, ее будет невозможно поддерживать. Если туда выносятся только самые важные данные, будет легко понять, какие данные уже покрыты.

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

JUnit 5

Я начал экспериментировать с тестами JUnit 5, управляемыми через данными, и обнаружил, что они очень читабельны в ходе выполнения.

Например:

static IntStream allPulperVersions() {
return IntStream.rangeClosed(1, ThePulperApp.MAXVERSION);
}
 
@DisplayName("Проверить, что количество элементов в меню верное")
@ParameterizedTest(name = "используя версию {0}")
@MethodSource("allPulperVersions")
public void checkMenuItemsMatchModel(int version) {
 
driver.get(url + "?v=" + version);
 
PulperNavMenu menu = new PulperNavMenu().getForVersion(version);
 
Assertions.assertEquals(menu.countMenuItems(),
menu.countAdminMenuItems() + menu.configuredNonAdminVersionMenuItems());
 
Assertions.assertEquals(menu.configuredNonAdminVersionMenuItems()+
menu.countAdminMenuItems(),
driver.findElements(
By.cssSelector("#primary_nav_wrap ul li")).size(),
"Неожиданное количество элементов меню в версии " + version
);
}

Это можно сделать читабельнее при помощи абстракций, чтобы упростить код-ревью утверждений – то есть спрятать driver.findElements и локаторы.

Однако результат будет достаточно читабельным.

Для повышения читабельности теста я использую @DisplayName, а не название метода.

Я использую @ParameterizedTest для прогона теста с разными параметрами, а имя – для того, чтобы сделать конкретный запуск теста читабельнее.

- NavigationViaMenuTest

- Проверить, что количество элементов в меню верное

- используя версию 1

используя версию 2

- используя версию 3

- используя версию 4

- используя версию 5

- используя версию 6

- используя версию 7

- используя версию 8

- используя версию 9

- используя версию 10

- используя версию 11

Что делать?

Рекомендую:

  • Сводить картирование (которое нельзя запустить как код) к минимум, потому что оно нуждается в поддержке, иначе вы начнете путаться – к примеру, в аннотациях, какие сторис покрыты этим @Test.
  • Сделать покрытие самодокументирующимся посредством эффективной структуры пакетов и наименований.
  • Использовать параметрические тесты, чтобы сделать данные видимыми и упростить ревью отчета о выполнении.
  • Использовать слои абстракции, чтобы сделать код читабельным, и максимально удерживать ревью покрытия на уровне кода.
  • Сравнивать органически созданный результат запуска тестов с моделью, чтобы найти специфические "зазоры" (к примеру, проанализировать результат работы прокси).
  • Использовать инструмент на основе DSL, если процесс ревью требует DSL, а покрытие можно максимально документировать при помощи данных, извлекая выгоду из возможностей DSL-инструментов по управлению через данные.

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

Статьи по теме

Множество моих ранних статей относилось к моделированию. Это ключевая часть тестирования.

Полезные ссылки