Уроки, извлеченные из поиска багов |
06.07.2022 00:00 |
Автор: Майкл Болтон (Michael Bolton) Эта история – комбинация недавнего опыта, который я просуммировал в едином рассказе. Паттерн впечатлений и откровений один и тот же, но, как говорят по телевизору, имена и детали были изменены для защиты невинных душ. Недавно я участвовал в тестировании онлайн-магазина. В приложении есть функция, отправляющая уведомления по электронной почте. На экране настроек этой функции для администратора в правом верхнем углу есть кнопки "Сохранить" и "Отмена". Эти кнопки не привязаны ни к каким клавишам. Пользователь должен или кликнуть на них мышкой, или перейти на них табуляцией и нажать Enter. Ниже и левее есть поля для изменения настроек. Затем в нижнем левом углу находится поле, куда пользователь вводит текст уведомления по умолчанию. Добавляем симпатичную короткую строчку в это текстовое поле, и все выглядит хорошо. Заполните поле целиком, и оно начнет расширяться вправо, чтобы вместить весь текст. Элемент, в котором находится текстовое поле, также расширяется вправо. Добавьте туда достаточно текста (нормальной для email-уведомления длины), и поле и его контейнер так разъедутся вправо, что начнут вываливаться за пределы экрана. И вот в чем штука: это начинает перекрывать кнопки сохранения и отмены в правом верхнем углу, и на них больше нельзя нажать. Текст можно удалить, но поле и контейнер остаются увеличенными. Они не уменьшаются, и кнопки остаются перекрытыми. Если походить по странице через Tab, можно хотя бы закрыть этот экран, но если вы к своему несчастью кликнули на "Сохранить" и вернулись в приложение, фронт-энд остается в скособоченном состоянии. В приложении есть файл настроек, но он закодирован – его нельзя просто отредактировать и подправить ширину поля, чтобы оно не перекрывало кнопки сохранения и отмены. Файл можно удалить, но если это сделать, вы потеряете множество других настроек конфигурации, и их придется вводить заново. Как мне сказали тестировщики, у компании был набор автоматизированных проверок для этого экрана. Мы заглянули в него. Проверки не включали никаких вариаций. Для поля уведомления они меняли значение по умолчанию на короткую строчку различных позитивных данных, а затем нажимали кнопку сохранения. Однако это была не экранная кнопка, а виртуальная. То есть даже в случае, когда тест включал бы проблемные данные, эти автоматические проверки все равно смогли бы найти и нажать невидимые, недоступные, виртуальные кнопки сохранения и отмены. Эти тесты ни под каким видом не смогли бы уведомить тестировщиков о существующей проблеме. При использовании поиска появлялся экран с листингом возвращенных поиском товаров. Некоторые варианты поиска возвращали один товар – одну карточку. Мы быстро обнаружили, что уход с этого экрана и возвращение назад к нему дублирует ту же карточку. Если сделать это еще раз, их станет три. За короткое время мы набрали достаточно карточек, чтобы достроить собор Гауди в Барселоне. Авторизация и добавление товаров в корзину работали хорошо. Добавление товаров в корзину с последующей авторизацией выглядело странно. Количество товаров на иконке корзины было верным и совпадало с добавленными нами товарами, но попытка перейти в корзину и что-то изменить вызывала сообщение, что корзина сейчас недоступна, что делало заказ невозможным. Черт, а я хотел купить эти книги) Мы нашли эти проблемы за несколько минут свободного несерьезного взаимодействия с продуктом с целью попытки поиска проблем. Мы сделали это, тестируя эмпирически. Мы взаимодействовали с продуктом таким образом, что наше поведение практически не отличалось от поведения пользователя, которого мы себе представляли. Большинство наблюдателей не отличило бы нас от пользователя, если бы наблюдатель не ставил целью замечать, как мы тестируем. Такой наблюдатель мог бы заметить, что мы на ходу проектируем и выполняем эксперименты, а также ведем заметки. Эти эксперименты основаны на представлении о данных и процессах, которые не указаны в требованиях или сценариях использования явным образом. Эти эксперименты нацелены на выявление уязвимостей и рисков, которые мы ожидали, представили, и выявили. Мы не пользовались продуктом с целью продемонстрировать, что все отлично работает. Мы делали это, чтобы его тестировать. И наши идеи не оставались статичными. Экспериментируя и взаимодействия с продуктом, мы узнали о нем больше. Мы спроектировали более богатые ментальные модели данных и их взаимодействия с функциями в продукте. Мы разработали наши модели на основании того, как люди могут использовать продукт, как они могут выполнять некоторые более сейчас предсказуемые действия – включая ряд ошибок, которые они могут совершить, и с которыми продукт может не справиться. Мы менялись, тестируя. Мы тестировали преобразовательным путем. Распознавая небольшие неуловимые намеки – вроде увеличения текстового поля, способного перекрыть или сделать невидимыми существующие данные при проматывании текста – мы выявили возможность уязвимостей и рисков, которую мы не предусматривали. Мы тестировали исследовательским образом. Мы не давали инструментам выполнять кучу беспризорной работы, чтобы затем оценить результаты, хоть этот подход и мог бы быть выгоден. Вместо этого тестирование получало пользу от прямого наблюдения и взаимодействий. Мы тестировали сопровождаемым образом. Мы не были ограничены заданной процедурой, скриптом, инструментами, служащими посредником между нами и продуктом и модифицирующими наше естественное с ним взаимодействие. Мы тестировали не инструментально, а эмпирически. Мы тестировали мотивированно, ища проблемы, с которыми люди могут столкнуться в ходе использования этой чертовой штуки. У автоматизированных проверок мотивации нет. Это нормально, они – просто продолжение людей, у которых мотивация есть, и эта мотивация побуждает их писать соответствующий код. Но даже несмотря на это эти проверки не выявили баг, и не сделали бы этого никогда в связи с различиями между тем, как продукт используется человеком и машиной. О, мы также нашли пачку других багов. Множество багов. В процессе этой работы мои тест-партнеры осознали кое-что еще. Видите ли, эта организация похожа на большинство: тестировщики обычно проектируют ряд сценарных тестов, а затем прогоняют их снова и снова – в целом это автоматизированные проверки, только без участия машины. Рано или поздно некоторые скрипты передаются программистам, превращающим их в настоящие автоматизированные проверки. Благодаря полученному опыту тестировщики заметили, что эти проблемы не были найдены ни тест-кейсами, ни автоматизированными проверками. Они осознали, что даже если у них есть задача создания формализованных процедур, то отличной идеей будет отложить проектирование, пока они не получат опыт взаимодействия с продуктом. Поработав с продуктом, тестировщики также обнаружили паттерн среди найденных проблем. Они поняли, что этот паттерн нужно обсудить на встречах по проектированию и предложить следить за ним в ходе ревью разработчиков, а также на уровне юнит-тестов и интеграционных проверок. Это в свою очередь означает, что в продукте останется меньше лежащих на поверхности багов. Это означает, что тестировщики потратят меньше времени на отчет об этих багов – а это означает, что они сконцентрируются на более глубоком, богатом исследовательском тестировании и найдут скрытые баги, сложные в выявлении. Они также осознали, что они, скорее всего, найдут ряд проблем в ходе раннего исследовательского тестирования и сообщат о них, и разработчики исправят эти проблемы и учтут их на будущее. Большее количество таких проблем после исправления не вернется никогда – крайне маловероятно, что после исправления эти участки кода будут затронуты так, чтобы конкретно эти проблемы появились снова. Это снизит нужду в длинных процедурных скриптах, ассоциируемых с этими проблемами – как максимум, краткого набора проверок будет достаточно. Самый быстрый способ написать скрипт – это не писать его вообще. Добавление автоматизированных проверок, ищущих эти проблемы, вряд ли будет нужным или желаемым вариантом. Помните, автоматизированные проверки исходно проблему не нашли. Тестировщики, писавшие код, могут сконцентрироваться на более низких, дружелюбных к машинам интерфейсах, тестируя бизнес-логику и требования, пока ошибки не просочились в интерфейс. В то же самое время эти тестировщики могут использовать код для генерации богатых наборов данных, и использовать код для прогона этих данных через продукт. Эти тестировщики также могут создавать инструменты, визуализации и парсеры логов, которые помогут команде увидеть интересные и информативные паттерны в результатах. Или же они могут создать действительно интересные, мощные и богатые формы автоматизированных проверок, как в этом примере (использование функции упаковки против функции распаковки – очень хорошее приложение эвристики "вперед-назад"). Один из наилучших способов "высвободить время для исследовательского тестирования" – это автоматизировать некоторые проверки, особенно на уровне разработчиков. Однако другой отличный способ высвободить это время – это автоматизировать меньше дорогих, сложных проверок, требующих от разработки и поддержки много сил, но не находящих реальных багов. Некоторые проверки ценны, быстры и дешевы. Самая быстрая, дешевая проверка, которую вы можете написать – это ненужная проверка, которую писать не надо. Сопровождаемое, исследовательское, мотивированное, преобразующее, эмпирическое тестирование – хороший способ разобраться, что есть что. |