Exploratory Testing: три истории применения тест-дизайна
Меня зовут Алексей Чаплиц. Имея за плечами более 20 лет опыта вне IT-индустрии, я стал тестировщиком ПО три года тому назад. Больше о том, как и почему я стал Software Tester, можно узнать из моего интервью ведущим подкаста QAGuild.
Это статья — моя первая проба пера в сфере тестирования, в частности на тему Exploratory Testing. Моя главная мотивация — поделиться небольшим опытом и ноу-хау с теми, кому это может пригодиться.
Под термином Exploratory Testing я понимаю не столько «свободный» стиль ручного тестирования, сколько осмысленное и систематическое, хотя и творческое, исследование причинно-следственных связей. Цель такого тестирования — оптимизация работы тестировщика, а его итог — отсутствие дорогостоящего устранения багов на продакш-уровне и наличие качественного продукта.
В статье читатель найдет три истории. В каждой описаны по одному методу тест-дизайна, которые я, зная того или нет, применял. Их анализ сделан задним числом (постмортем). Больше об этих методах можно узнать в книге «Explore It!» Элизабет Хендриксон.
История первая: как C.R.U.D. помог мне проверить GUI
Пару лет назад я присоединился к небольшой, но распределенной команде разработки, которая состояла из пяти человек — Requirements Engineer/PO/UX Designer (в одном лице), двух разработчиков и двух заказчиков-инженеров из отдела R&D.
Я получил задачу тестирования ПО для работы с файлами
Контекст тестирования
Перед тем, как я присоединился к команде, наш Requirements Engineer проделал много качественной работы по составлению требований и пользовательских историй для создания основных функций. Вместе с заказчиками он тестировал эти функции по мере их появления. Однако при этом не существовало каких-либо записанных тестовых кейсов для регрессионного тестирования.
Использованная техника тест-дизайна
Книга «Explore It!» описывает простую, но эффективную пошаговую технику тест-дизайна — C.R.U.D. (Create, Read, Update, Delete). Обычно она применяется для проверки различных элементов в реляционных базах данных со структурой parent-child. Я применил этот подход для тестирования GUI вышеупомянутых станков, в которых использовались файлы с такой же структурой.
Шаг 1: Create (создание файлов)
В качестве тестовых файлов я подготовил вышеупомянутые файлы. Это позволило протестировать основные функции приложения, такие как загрузка, редактирование и их открытие в UI. Эти действия стали шагами для позитивных тестов.
Однако для создания негативных тестов я редактировал тестовый файл, заменяя параметры нужного типа на неприемлемые, например, int вместо double. Таким образом создавал «новые» файлы.
Диалог с сообщением об ошибке после введения параметра недопустимого типа
Шаг 2: Read (чтение файлов)
Чтение файлов было частью позитивных и негативных тестов. Программа должна была сработать так, как ей было положено, а именно открыть неиспорченный файл или показать диалог с соответствующим сообщением об ошибке.
Я также проверял способность программы работать под нагрузкой, то есть открыть и прочесть сотни валидных и невалидных файлов.
Диалог с сообщением об ошибке при открытии испорченного файла
Шаг 3: Update (обновление файлов)
Программа позволяла обновлять данные в файлах — как внутри программы, так и снаружи. При этом она должна была оповестить об изменениях в соответствующем диалоговом окне с возможностью сохранить их. Для проверки этого функционала я либо вносил изменения в параметры в UI или в текстовом редакторе в то время, как этот файл был открыт в программе, затем закрывал его.
Шаг 4: Delete (удаление файлов)
Для проверки функционала предупреждения об удаленных/несуществующих файлах я открывал их в программе, удалял на локальной машине, а затем сохранял (см. фото тестовой сборки). Программа показывала диалог с соответствующим предупреждением.
Тестовая сборка в TestRail для проверки функционала предупреждения об отсутствии запрошенных файлов
Результат анализа поведения тест-объекта
Программа работала большую часть тестов, как и ожидалось, под нормальной и стрессовой нагрузкой. И это благодаря тщательно проделанной работе Requirements Engineer’а и разработчиков каждый спринт.
Несколько тщательно выписанных пользовательских историй для стартовой страницы приложения
Что можно было изменить
В общем и целом, жаловаться мне было не на что, за исключением создания тестов для сложного функционала. В данном случае я просил помощи у команды.
Вывод
C.R.U.D. (Create, Read, Update, Delete) — простой и эффективный метод тест-дизайна. Я рекомендую его к применению по назначению, то есть в реляционных базах данных, или в аналогичных кейсах. Если вы знаете о противопоказаниях для использования метода, пишите в комментариях к статье.
История вторая: как я определял покрытие тестами больших рисков
На новом проекте (речь о нем пойдет подробнее в третьей истории), куда я пришел на замену выбывшего тестировщика, было три уровня тестирования, с тремя командами и тестовыми кампаниями. Я стал членом третьей команды, которая занималась регрессионным и smoke-тестированием еженедельных релизов и их хотфиксов.
Контекст тестирования
В проекте уже существовали тестовые кампании для наших целей. И хотя они покрывали основной функционал, из их содержания и описания нельзя было понять, покрывали ли они большие риски. Для того чтобы убедиться в этом, я применил технику тест-дизайна из книги «Explore It!».
Использованная техника тест-дизайна
Книга предлагает следующие три шага:
- Составить список стейкхолдеров «в теме» (ПМ, ТМ и другие) для сбора информации.
- Узнать у них о текущих жалобах и будущих страхах, связанных с продуктом.
- Проверить базу данных (например, в Jira или в Вики проекта) с описанием критических багов и их кластеров.
- Протестировать с помощью известных техник с граничными переменными, вариациями данных, состояний и т. п.
Этот подход имеет элементы классического управления рисками проекта и продукта, а его успех зависит от качественного анализа (см. первые три шага). Как оказалось, именно он стал моим главным фокусом.
Шаг 1: Составить список стейкхолдеров «в теме»
Вот как выглядел мой список:
- Release/Test Manager;
- Incident Manager/руководитель службы поддержки;
- модератор пользовательского форума;
- Product Manager;
- разработчик приложения.
Шаг 2: Узнать у стейкхолдеров о текущих жалобах и будущих страхах, связанных с продуктом
Вот такие вопросы я задал каждому из стейкхолдеров:
- Release/Test Manager: существует ли анализ взаимосвязей между элементами архитектуры приложения с точки зрения рисков? Анализ явных и неявных ожиданий пользователей? Области для улучшения и их приоритизация? (см. фото с примером анализа House of Quality).
- Incident Manager/руководитель службы поддержки: какие самые «горячие» проблемы пришлось решать за последний месяц? Результаты их причинно-следственного анализа?
- Модератор пользовательского форума: что обсуждают больше всего на форуме (от 200 уникальных посещений темы)?
- Product Manager: какой функционал используется более всего? Какой приносит больше дохода (например, предоплата услуг)?
- Разработчик приложения: существует ли список с кодом ошибок, чтобы найти риски, еще не покрытые тестами?
Пример анализа House of Quality
Вдобавок к этому я сам провел анализ важных для бизнеса рисков, пользователей, с точки зрения функционала и технологий. Для этого использовал 16 вопросов из чек-листа, а также данные «радара» рисков, которые получил у менеджмента.
«Радар» рисков
Шаг 3: Проверить базу данных с описанием критических багов и их кластеров
Проанализировав найденную информацию в Jira, я установил, насколько эти проблемы покрыты существующими тестовыми сборками.
Шаг 4: Протестировать с помощью известных техник с граничными переменными, вариациями данных, состояний и т. п.
Этот шаг я не применял (см. результат анализа ниже).
Результат анализа поведения тест-объекта
В итоге проведенного анализа я обнаружил, что большая часть критических багов и рисков, связанных с ними, возникали на ранних стадиях разработки. Они были покрыты тестами на ранних уровнях тестирования.
Однако, учитывая, что эти баги регулярно появлялись на нашем уровне и даже у пользователей, я составил список из уже существующих тестовых кейсов для целенаправленного покрытия рисков. Тестировать по этому списку я мог только тогда, когда у меня было на это время.
«Ты сделал двойную работу!» — скажет читатель. Согласен. Однако я смог убедиться в том, что большие риски были покрыты сборками. До этого момента, это было не очевидно на моем уровне тестирования.
Что можно было изменить
Я поделился своим подходом к тестированию на основе рисков и его первым результатом с коллегами и тест-менеджером. Однако это не вызвало у них какого-либо отклика. У них не было ни желания, ни времени отвлечься на изучение и применение нового метода тест-дизайна. Думаю, что это не помешало бы тогда.
Применив подобный подход, можно было бы:
- Отточить этот метод после итеративного использования, обсудив его первое применение.
- Проводить сессии оценки рисков по методу, описанному выше (или любому другому), с регулярностью раз в два-три месяца.
Вывод
Метод тест-дизайна помог подтвердить тот факт, что большинство явных и неявных рисков были покрыты тестовыми сборками. Однако одно дело, когда это сделано непрозрачно для тестировщиков, а другое, когда целенаправленно. В последнем случае, применяя регулярный анализ рисков, можно улучшить качество продукта.
История третья: как я «ловил» невоспроизводимый баг
Мое задание на этом проекте было непростым. Оно состояло в том, чтобы автоматизировать с помощью специального инструмента сценарии ручных тестов для Streaming Media Box (далее SMB). SMB — это приставка мультимедийных потоков, которую мой тогдашний работодатель — телекоммуникационная фирма — активно поставлял десяткам тысяч своих клиентов (см. фото).
Streaming Media Box (приставка мультимедийных потоков) с ПУ
Будучи новичком в автоматизации, я медленно, но уверенно двигался вперед к целям проекта, пока не уперся в невоспроизводимый баг, который блокировал принятие менеджером целой тестовой сборки. Что было делать?
Контекст тестирования
Тестовая сборка состояла из четырех тестов, которые создавали, использовали, а затем удаляли пользовательский профиль с одним и тем же именем на нескольких SMB.
Скриншот экрана ТВ с пользовательскими профилями с разными именами
Создание профиля состояло из четырех этапов:
- Создание профиля с помощью программы на SMB.
- Верификация через SSO (Single Sign-On — одноразовую регистрацию) для сохранения на главном сервере.
- Передача параметров созданного профиля с главного профиля через прокси-сервер на SMB. В то же время, создание профиля с любым другим именем было всегда возможно.
- Появление созданного профиля в UI на SMB. На фото представлен скриншот экрана ТВ с пользовательскими профилями с разными именами.
Обычно создание и удаление профиля на первом SMB шло успешно. Однако после того, как профиль с таким же именем создавался на другом SMB, во время повторного запуска, программа зависала, и вся тестовая сборка падала. Профиль с тем же именем нельзя было снова создать на первом SMB. Мои вопросы к создателям тестового инструмента, которые запускали эти же тесты, имели один и тот же ответ: проблема находится в ПО SMB, а не в тестовых скриптах.
Мои дальнейшие расспросы показали еще более сложную картину. Несколько разных людей в свое время создавали тестовую сборку для ручного тестирования. Никто из них не пытался выяснить, при каких условиях и когда точно тесты падали, а воспроизвести этот баг руками было почти невозможно. Кроме того, менеджмент не считал приоритетом исследование проблемы и не давал на это время. Однако я взял на себя смелость и попробовал разобраться в причине падения тестовой сборки.
Пошаговое решение проблемы
Книга «Explore It!» предлагает «поймать» невоспроизводимый баг в четыре шага:
- Собрать доказательства, и на их основании найти закономерности появления бага.
- Провести мозговой штурм факторов, которые окружают или усугубляют проблему.
- Использовать модель состояний (state models) для фиксации времени появления проблемы.
- Провести предметное обсуждение проблемы с экспертами, которых она затрагивает.
В своем анализе (уже задним числом) я использовал шаги 1, 2 и 4.
Шаг 1: Собрать доказательства, и на их основании найти закономерности появления бага
- Когда появился баг? — Он появлялся сразу после того, как создавался профиль с тем же именем на другом SMB, и вся тестовая сборка запускалась повторно.
- Какова была связь между тестовыми объектами при появлении бага? — Как только на двух SMB был создан профиль с одним и тем же именем, повторное создание нового профиля с тем же именем на первом SMB было невозможно, а вся тестовая сборка падала.
- Просматривается ли здесь некая закономерность? — Было очевидно, что профиль на втором SMB как-то мешал повторному созданию профиля с тем же именем на первом SMB. А с любым другим именем было всегда возможно.
Шаг 2: Провести мозговой штурм факторов, которые окружают проблему
1. Что говорят другие тестировщики? Первая идея: таймауты (периоды ожидания) перед исполнением автокоманд в скриптах недостаточны. Однако они были вполне достаточны для ожидания ответа от бэкенда.
Вторая идея: скрипт автотеста исполняет команду «Нажать ОК» множество раз в то время, пока клиент регистрируется через SSO на главные сервер. Но, как показала проверка, многократное нажатие кнопки ОК не останавливало создание профиля с любым другим именем.
Третья идея: профиль с тем же именем уже существует на одном из нескольких SMB после первого удачного запуска тестовой сборки. Это уже было известно и подтверждало некую закономерность.
2. Что говорят инженеры, ответственные за бэкенд? Первая идея: аккаунт созданного профиля имеет скрытые детские профили, оставленные после ранних тестов, которые не отображаются в UI SMB. Проверка и удаление таких профилей в кабинете пользователя, однако, не решило проблемы.
Вторая идея: однажды созданный профиль никогда не удалялся с главного сервера. Проверка подтвердила этот факт и указала на ранее описанную закономерность.
Шаг 3: Использовать модель состояний (state models) для фиксации времени появления проблемы
Этот этап не применялся полноценно в анализе. Время появления бага было обнаружено на первом этапе анализа (см. п.1 выше).
Шаг 4: Провести предметное обсуждение проблемы с экспертами, которых затрагивает проблема
«Случайный» разговор с любознательным администратором бэкенда из Голландии, который прибыл на квартальное планирование в наш офис, помог мне посеять начальный интерес к теме. В результате завязалась длительная переписка в Slack-чате по этой проблеме с видео- и текстовыми логами. В свою очередь, это помогло мне поддерживать в нем интерес к ее решению.
После обсуждения с сисадмином из Голландии я поднял снова проблемный вопрос перед руководством. В итоге этот администратор снова открыл обсуждение вопроса в уже существующем тикете в Jira. В конце концов, он удалил у себя на сервере профиль с тем же именем, который был создан на другом SMB и — о, чудо! — проблема падающей сборки решилась сразу. Теперь им надо было работать над тем, чтобы этот профиль удалялся всегда.
Результат анализа поведения тест-объекта и взаимодействия участников
- Следующая закономерность поведения тестовых объектов четко прослеживалась: создание профилей с одним и тем же именем на двух SMB заставляло сборку падать.
- Программа не предусматривала появление диалога с предупреждением о том, что создание одноименного профиля на другом SMB нежелательно.
- Тестировщики не создали тестовую сборку, которая бы целенаправленно тестировала взаимосвязь SMB — SSO — прокси-сервер — главный сервер. (Показать пример конкретной системы я не могу из-за NDA, но думаю, что что-то подобное можно найти в сети.)
- Простое решение проблемы заняло много времени и сил. Это я могу отнести только к человеческому фактору.
- Взаимосвязанные тесты склонны иметь проблемы, которые тяжело вычислить.
Что можно было изменить
Во-первых, проблему могли предотвратить инженеры бэкенда, если бы дали доступ тестировщикам к документации о взаимодействии различных элементов архитектуры сервиса и назначили созвоны с ними в случае возникновения вопросов.
Во-вторых, по возможности избегать создания сборок из взаимосвязанных тестов, которые имеют «встроенный» потенциал проблем.
В-третьих, менеджменту стоило бы делегировать создание и поддержку тестовой сборки одной команде, чтобы избежать потери времени и важной информации.
В-четвертых, решение проблемы можно было ускорить, если бы ею занялись все вместе и как можно раньше.
Вывод
Индуктивный метод (от деталей — к закономерностям) анализа проблемы невоспроизводимого бага, предложенный в книге «Explore It!», помог, пусть и постмортем, проследить разрешение проблемы падающей тестовой связки. Его этапы могут служить схемой решения подобных проблем.
Буду рад узнать о вашем опыте в Exploratory Testing. Делитесь им в комментариях. Спасибо!