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

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

.
Лучше поговорим о поведении
20.09.2022 00:00

Автор: Баз Дейкстра (Bas Dijkstra)
Оригинал статьи
Перевод: Ольга Алифанова

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

Если вы пропустили статью в LinkedIn, о которой я говорю (что вполне понятно, учитывая врожденную ускользающую природу контента социальных сетей), вот ряд примеров, которые я использовал для подкрепления своей позиции:

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

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

Почему нет?

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

Завершенный заказ, выдача нужных данных, срабатывание процесса пакетной обработки – все это двигает бизнес-процессы на шаг вперед к завершению.

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

Неужели мы не хотим убедиться, что наш магазин не может продать алкоголь подростку? Неужели мы не хотим проверить, что система не принимает "банан" как дату? Неужели не стоит посмотреть, что API вернет 404 при попытке получения данных от несуществующего ресурса? Не надо ли посмотреть, выдает ли наш код ожидаемое исключение, когда мы вызываем метод с особыми значениями параметров?

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

Я бы сказал, что вышеописанные тесты могут быть настолько же важными – или даже больше, - чем те, которые мы обычно называем "позитивными". Дабы предотвратить недосмотр, забывчивость или даже пропуск таких тестов, мудро было бы перестать пытаться делить их на "позитивные" и "негативные", и рассматривать их как аспекты поведения нашего приложения в целом.

Именно поэтому я считаю такие техники, как Карта Примеров и Карта Характеристик, обычно используемые в разработке, управляемой через поведение, и исследовательское тестирование в целом, такими полезными: они упрощают тестировщикам и командам разработки возможность взглянуть за пределы того, что "должен делать продукт", и тщательно подумать о том, "какое поведение пользователя продукт должен предотвратить".

Или, как я иногда формулирую, это помогает командам разработки перейти в "Режим Ди Ди", идентифицируя и обсуждая все типы поведения, а не только желательные с точки зрения конечного пользователя.

О (не)функциональном тестировании

Наряду с "позитивными" и "негативными" кейсами в тестировании есть еще одно деление, которое надо бы переосмыслить – разделение тестов на "функциональные" и "нефункциональные". В первом случае речь обычно идет о том, способно ли ПО выполнять действие, двигающее нас вперед на пути завершения бизнес-процесса или получения результата:

  • Можем ли мы положить один или несколько товаров в корзину и перейти к оплате, чтобы товары были заказаны и доставлены?
  • Можем ли мы ввести адрес почты в поле "email" в форме заказа?
  • Возвращает ли наш API искомые нами данные при отправке валидного запроса?
  • Возвращает ли наш метод объект верного типа с верными свойствами, когда мы вызываем его с определенными параметрами?

Заметьте, что в свете вышеизложенного эти примеры можно классифицировать, как "позитивные" "функциональные" тест-кейсы. Я мог бы легко включить сюда "негативные" "функциональные" примеры (пардон за большое количество кавычек).

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

По какой-то причине эти тесты часто оказываются (иногда намного) ниже в списке приоритетов команды разработки: много времени и сил тратится на разбирательство, способно или нет наше ПО поддерживать бизнес-процесс или результат, а эти "нефункциональные" характеристики ПО зачастую слабо представлены в тест-деятельности.

Но ведь производительность, безопасность, доступность и другие "нефункциональные" характеристики – это просто другие аспекты поведения нашего ПО в целом! И если так, то почему они так часто плохо представлены в тест-стратегии и подходе? Неужели они не настолько важны?

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

Почему же тогда мы тратим относительно мало времени и внимания на исследование этих аспектов поведения нашего ПО? Многие команды прилагают усилия для того, чтобы грамотно встроить "функциональное" тестирование и автоматизацию в жизненный цикл своих приложений – например, практикуя BDD, используя подход "сначала тест", практикуя парную работу разработчиков и тестировщиков над созданием приложения и кода функциональных тестов, и так далее.

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

Или, формулируя иным образом: когда вы в последний раз обсуждали производительность, доступность или безопасность в ходе обсуждения детализации?

Да, знаю, правильная подготовка и проведение тестов производительности, безопасности или доступности ПО требует определенных навыков, включая, но точно не ограничиваясь знанием, как обращаться со специальными инструментами тестирования этих аспектов. Но аргумент ли это для того, чтобы "нефункциональное" тестирование так часто оставалось сбоку-припёку (если о нем вообще подумали) в тестировании и разработке?

У меня пока нет хорошего решения этой проблемы, но думаю, что хорошим первым шагом будет перестать делить тесты на "функциональные" и "нефункциональные", и начать говорить о поведении нашего ПО в более целостной манере, выходя за рамки верификации "может ли продукт делать то, что он должен делать?"

Обсудить в форуме