О курсе
Это практический курс: теории минимум. Типичная лекция — на 10-15 минут. Короткая лекция «как это применять» и тут же практика! Конечно, есть и сложные лекции (на 30 минут). Есть и короткие, на 7 минут. Нет жесткой привязки ко времени лекции. Сколько надо дать теории, столько и говорю, а дальше уже практикуйтесь.
Для локализации багов мы будем применять техники:
- Черного ящика — как понять, что происходит, если нет доступа в код.
- Белого ящика — куда можно посмотреть в коде? Смотреть будем на примере приложения folks с открытым исходным java-кодом. Разумеется, у вас на проекте код будет выглядеть по-другому, но зато вы получите представление, где там могут вылезти баги. Баги, которые мы будем рассматривать на курсе, не были внесены в приложение нарочно — так что все приближено к реальности.
Лекции идут в фирменном стиле тренера, с картинками. Посмотрите примеры видео на youtube-канале тренера, чтобы понять, подходит ли вам такой стиль изложения.
Если вы переживаете, что не сможете что-то сделать (например, задания на просмотр кода), вот вам задача для самопроверки — соберите проект folks и запустите тесты. Инструкция есть, есть даже видео-инструкция по установке java, maven на Windows, Если справитесь, то и все остальное будет вам по плечу!
Программа курса
0. Введение
Что такое локализация и зачем она вообще нужна тестировщику.
Как умение локализовывать задачи экономит время команды и убирает панику.
Как знание о типовых проблемах помогает воспроизводить баги, которые «не воспроизводятся».
1. Уточнение устройств, на которых есть баг
На что обращать внимание при багах «поехала верстка», «текст вылезает за пределы экрана».
Как понять, в какой момент едет верстка? Какие инструменты использовать:
— как замерить размер окна;
— какие есть линейки;
— как посмотреть размер окна в консоли.
2. Исследование состояний
Изучим разные состояния объекта. Если проблема при сохранении — а кого мы вообще сохраняем?
— свежесозданную карточку
— отредактированную
— удаленную
…
Если у нас есть пользователь, то какой он? А как регистрировался? Как это может повлиять на воспроизведение бага?
3. Использование классов эквивалентности и граничных значений
Что такое классы эквивалентности.
Почему на границах встречаются баги.
Зачем тестировать ноль и как его найти, если у нас не строка ввода?
4. Опровержение своих теорий
Как опровергать свои теории и зачем это нужно.
— метод «найди 5 отличий»;
— принцип минимализма (отсеивание лишнего).
5. Метод бисекционного деления
Что такое бисекционное деление.
Как его использовать тестировщику для локализации бага.
Как оно используется в разработке и к каким проблемам может привести.
6. Чтение логов
Что такое логи. Что в них записывается?
Как читать логи. Как читать стектрейс ошибки.
Логи на сервере и на клиенте.
7. Просмотр запросов с клиента на сервер
На клиенте помимо JS-логов можно смотреть, что вообще ушло на сервер.
Это помогает понять, где произошла ошибка и кто виноват: клиент или сервер. Учимся это делать.
8. Воспроизведение «от обратного»
Техника расследования закрытой комнаты. Наиболее актуальна для багов с кэшом.
Вот есть баг, из кэша достаются неправильные данные. Как воспроизвести? Идем от обратного, пытаемся получить “плохие данные” разными путями.
9. Проверка по коду
Как читать код, при условии, что разработчики идут вам на встречу и разделяют потроха логики и описание объектов.
Читаем java-объект и схему создания БД. Выверяем их на соответствие друг другу.
Внимание: у вас на проекте может быть не java, но принцип все тот же. На примере домашнего задания вы увидите, как можно найти баг, исследуя код
10. Проверка соответствия типов данных
Если поле встречается в коде несколько раз:
— в объектной модели;
— в схеме создания БД;
Важно проверять соответствие типов. Смотрим, какие встречаются баги на несоответствие типов.
11. Проверка стыка интеграции
Какая бывает интеграция между системами.
Какие бывают баги на стыке интеграции.
Куда смотреть в первую очередь.
12. Проверка данных после миграции
Зачем тестировщику нужна как чистая база, так и база, живущая веками?
Примеры ошибок, вылезающих после миграции и почему они не ловятся на свежей тестовой БД.
13. Проверка concurrency
Типичная ошибка — выполнение CRUD над одним пользователем. Тестировщик может найти баги, переключаясь между вкладками интерфейса. Но это про поиск багов, а не про локализацию, казалось бы, да?
Но о concurrency важно знать, так как параллельная работа может быть и на другом уровне:
- Идет забор данных из базы по 1000 записей за раз. Что, если в этой 1000 встретились 2 одинаковых клиента? Строка базы заблокирована первым изменением — второе разваливается.
- Интеграция по SOAP \ REST. Если запросов много, там тоже можно влететь на изменение одного и того же клиента.
И в этом случае к вам придут “у меня тут ошибка”, а вы понять не можете, откуда она взялась, так как текст невразумительный. Надо помнить про параллельную работу, чтобы локализовать причину.
14. Заключение
Вопросы и ответы
1. Можно ли проходить курс на Linux или Mac?
Да, он не зависит от вашей OS
2. Какие знания нужны для курса?
Общие знания о тестировании — что это вообще такое, как составлять тесты, что такое классы эквивалентности.
Базовое понимание языка программирования (любого) — вы не должны падать в обморок от слов string или «тип данных». Но все, что будет нужно для ДЗ, я объясню.
Умение устанавливать новые программы — мы будем смотреть в код, а для этого нужно будет установить java, mercurial, maven. Вот инструкция, соберите проект перед записью на курс.
3. Будет ли мне интересно, если я проходил другие ваши курсы?
Если вы прошли «Школу для начинающих тестировщиков» в группе, то встречались с багами в коде folks — но эти задания на курсе необязательные! Так что сильно не влияют на интерес.
Если вы прошли «Логи как инструмент тестировщика», то уже сделали пару обязательных заданий. Но всё равно будет много нового и полезного
4. А скидку то дадут мне за эти ДЗ?
Да, покажите ваш сертификат и получите скидку:
- Логи как инструмент тестировщика → 20%
- Школа для начинающих, пройденная в группе → 10%
Формат
14 теоретических занятий + много практических заданий для самостоятельной работы + постоянные консультации тренера в чате.
Два раза в неделю в неделю по понедельникам и четвергам до 12.00 по Московскому времени выкладываются теоретические лекции, ссылки на дополнительные материалы, домашняя работа.
Теоретическую информацию можно посмотреть в любое удобное время.
Помимо теоретической части, вас также ждут практические задания для самостоятельной работы, которые вы можете прислать тренеру на проверку. После проверки практических заданий Вы получаете подробный комментарий по своей работе и при необходимости советы по доработке. По результатам комментариев тренера Вы можете переделать работу и отправить ее тренеру еще раз.
Общение участников курса и тренера проходит и в чате группы, где можно задавать вопросы тренеру и при желании общаться с другими участниками группы. Вы можете задавать вопросы по теоретическому материалу или практическим работам, как только они у вас возникают.
Все выпускники, успешно сдавшие домашние задания, получают сертификат.
Материалы курса доступны в течение года с даты окончания.
Условия
Стоимость участия для физических лиц: 5 500 рублей за весь курс.
Стоимость участия для юридических лиц: 7 500 рублей за весь курс за одного участника. При регистрации от 3-х участников на один курс действует 15% скидка.
Организатор мероприятия: ИП Назина Ольга Евгеньевна, ИНН 772791965180, ОГРНИП 315774600011282
Услуги оказываются на основании публичного договора оферты. Ознакомиться с договором можно ЗДЕСЬ.
Если Вы хотите оплатить тренинг прямо сейчас, то нажмите кнопку выше (если кнопка активна, значит можно оплачивать не беспокоясь о наличии мест). После оплаты мы пришлем письмо о регистрации на курс и подтверждение оплаты. Если Вы не получили письмо в течение рабочего дня, просто отправьте сообщение на trainings@software-testing.ru
Если Вы хотите совершить оплату позже, для гарантированного участия обязательно забронируйте место на тренинге, для этого необходимо нажать на кнопку ЗАПИСАТЬСЯ справа от тренинга и заполнить все необходимые поля
Если у Вас есть какие-то вопросы, их можно задать по указанному выше адресу.
Информация для юридических лиц:
Для регистрации на тренинг и оформления договора и выставления счета на оплату нажмите кнопку Записаться, выберите пункт Организация и заполните все поля.
Обратите внимание, что при постоплате стоимость тренинга увеличивается на 25%.
В случае возникновения вопросов обращайтесь по адресу trainings@software-testing.ru.
Как локализовать плавающий баг
Плавающие баги (они же гейзенбаги) — это ошибки, которые возникают спонтанно во время выполнения одних и тех же действий и при одинаковых условиях. Такое поведение наблюдалось как минимум единожды, однако это поведение мы не можем воспроизвести повторно.
Поиск плавающих багов – это достаточно сложный процесс, который требует много времени и усилий для их локализации.
В этой статье своим видением по локализации плавающих багов с нами поделится Ведущий специалист по тестированию программного обеспечения, Сергей.
Основная задача инженера по тестированию: превратить плавающий баг в обычный, найдя пути его воспроизведения и тем самым облегчить исправление на стороне разработки.
Что для этого нужно сделать?
Первое: задать вопрос «Насколько найденный баг является критичным с точки зрения работы Приложения (нарушает ли основную работу функциональности) и насколько дефект важен для Бизнеса?». Важность обоснована тем, что на поиск причинно-следственной связи понадобиться большое количество времени проектной команды, однако сам баг может быть тривиальным (например, воспроизводится 1 раз из 100 для функциональности, которая не часто используется пользователями; поиск отрывает разработку от передачи новой функциональности в промышленную эксплуатацию).
Второе: собрать и проанализировать информацию по багу. Такую как: где воспроизводится баг, при каких условиях, какие шаги для воспроизведения и т.д.
Здесь информацию можно разделить на 2 типа:
- Техническую информацию о проблеме. Например, можно:
- настроить и проанализировать полученные логи по системе, где воспроизводится баг;
- использовать программы отладки совместно с разработчиками;
- провести анализ результата мониторинга проблемы и т.д.
Существуют следующие подходы к локализации плавающего бага:
- Тестирование на грани возможностей. Этот метод заключается в том, чтобы проводить тестирование при крайних условиях, например, при максимальной нагрузке на систему или при использовании нестандартных настроек. Таким образом, вы можете обнаружить ошибки, которые не проявляются при обычном использовании системы. Однако этот метод может быть очень трудоемким и затратным, а также требует специализированных знаний по проведению нагрузочного тестирования и настройки окружения.
- Использование инструментов для автоматического тестирования. Этот подход позволяет использовать специальные инструменты для генерации и запуска тестовых случаев для системы. Тем самым мы можем проверить большее количество сценариев и данных за короткое время, и повысить вероятность обнаружения багов. Например, использование Selenium позволяет автоматизировать тестовые сценарии для веб-приложений, а Appium— для мобильных приложений.
- Применение техник ручного тестирования. Подход заключается в том, чтобы проводить тестирование вручную, используя различные сценарии использования системы. Например, воспроизвести тестовый сценарий в той последовательности, в которой был найден баг, далее сужать сценарий (от общего к частному) для локализации проблемы или наоборот использовать подход от частного общего (вариант зависит от контекста проблемы).
Выбор подхода зависит от конкретной ситуации, обладания специальными знаниями и возможностями их применения, наличия времени на поиск у специалиста. Важно помнить, что всему всегда есть логическое объяснение и у всего есть причинно-следственная связь. Ваша главная задача — ее найти!
Мы благодарим Сергея за уделенное время на интервью и за развернутые ответы.
Пользуясь случаем, поздравляем всех Тестировщиков с прошедшим профессиональным праздником! Желаем вам всего самого лучшего и светлого, чтобы приходили только интересные задачи и всегда были перспективы для дальнейшего развития и самосовершенствования. Спасибо за ваш труд и вклад в общее дело!
Плавающие баги: основные ошибки и как охотиться.
Однажды тестировщик Петя заходит на следующий день после релиза новой версии в комментарии к своему проекту и видит сообщения об ошибке.
Петя вспоминает, что как-то уже встречал эту ошибку, но она ни разу не повторилась. Он, разумеется, сразу же перепроверяет все кейсы, связанные с сообщениями пользователей, но у него всё точно по ТЗ и никаких ошибок.
Так Петя встретил свой первый плавающий баг.
Давайте подробнее рассмотрим, что же это за баги такие и где они плавают.
Для начала нужно узнать, что такое плавающий баг.ПЛАВАЮЩИЙ БАГ – это ошибка, которая в одних и тех же условиях то воспроизводится, то нет.
Однако важно понимать, что любая ошибка, даже плавающая, имеет причины появления. И поиск причины – самое сложное в охоте на плавающий баг.
Основные ошибки при охоте
Какие ошибки может допустить Петя при охоте на свой первый плавающий баг?
1. Ринуться с головой в выяснение причин.
Так делать не стоит. Важно сразу понять, насколько ошибка критична, и, уже отталкиваясь от этого, действовать или…Или оставить всё как есть. Потому что поиск плавающих багов – это всегда большие затраты времени не только QA отдела, но и отдела разработки.
Также не стоит паниковать: баги не вызваны злыми духами и в каждом проекте их в избытке. Просто большинство себя либо не проявило, либо не было замечено.
Также важно удостовериться, что баг действительно плавающий. Будет весьма глупо потратить много часов своей (и вдобавок чужой) работы на отлов ошибки, фикс которой вы пропустили.
Также стоит убедиться, что ошибка является так называемым тестировщиками “лотерейным” багом, то есть багом, всплывающим из-за выпадения какого-то рандома в проверяемом ПО.
2. Накосячить с оформлением тикета в баг-трекере.
Для исправления ошибки разработчику важно иметь максимум полезной информации и минимум бесполезной. Если всё же ошибка критическая и мы беремся за её поиск, то необходимо взять кейс, при котором хотя бы единожды воспроизвелся баг, и пройти его несколько раз. Также по возможности исключить некоторые пункты. Особенно критически нужно относиться к словам очевидцев (пожаловавшихся пользователей). Потому что пользователь без труда что-нибудь напутает, а вас в ваших поисках это уведет совершенно не в ту степь.Как охотиться?
А дальше есть множество способов работы, которые можно применять и каждый из них по-своему хорош:
1) Подключите к процессу стороннего человека, а лучше нескольких. Свежий взгляд часто замечает то, что вашему замыленному взгляду кажется несущественным.
2) Ищите инструменты, которые помогут вам точнее отслеживать проблему. Например, логи проекта (технические сообщения от программы, падающие в консоль или её аналог) позволят вам не ломать голову над тем, как же воспроизвести только что сломанное ПО. А вместо этого сразу отдать разработчику то, что укажет, что именно сломалось под капотом программы.
3) Налаживайте коммуникацию с пользователями. Спрашивайте детали у тех, кому не повезло столкнуться с плавающей ошибкой. Возможно, именно их помощь будет ключевой. Но не будьте излишне уверены в чужих словах.
4) Поищите в списке багов похожие проблемы. Иногда информация о похожих багах помогает в исправлении.
5) Упрощайте и усложняйте всё. Меняйте переменные. Упрощение поможет точнее локализовать баг, а усложнение приведет к проверкам, казалось бы, несвязанных вещей или нахождению лотерейных багов, о которых мы говорили выше.
6) Провести стресс-тесты. Возможно, ошибка случилась из-за чрезмерной нагрузки.
7) Поговорите с разработчиками о том, чтобы поставить “ловушку” (функцию в программе, сообщающую о том, что что-то не так), которая даст необходимую информацию.
8) Если ничего не помогает, то дайте проблеме отлежаться. Может, она решится сама собой, а может, вы найдете необходимую информацию.
_______
Пост написан совместно с одним из наших преподавателей (Андрей Высоцкий).
В следующем посте рассмотрим, как на практике происходит поиск плавающих багов и поговорим про ошибке, которые допускаются при их поиске.Home
Способность уверенно исследовать плавающие баги – одна из характеристик отличного тестировщика. Самые захватывающие истории, которые я слышал от тестировщиков, были про охоту на «белых китов» в океане сложного кода.
В отличие от багов, которые загадочным образом воспроизводятся постоянно, плавающий баг – это больше проблема тестирования, нежели разработки. Многие программисты просто не хотят гоняться за причинами таких проблем, если есть куда более доступные жертвы.
Вообще-то плавающие баги не должны вас удивлять. Все программирование, можно сказать, крутится вокруг контроля неустойчивого поведения. Итак, о чем речь?
Нас не беспокоит неустойчивое поведение, если оно а) так и задумано б) не несет в себе тайны, даже если оно не вполне предсказуемо. Например, результат подброшенной монеты или шанс выбить 777 в игровом автомате – вполне себе неустойчивое поведение. Даже загадочное неустойчивое поведение не волнует нас, если мы уверены, что оно не вызовет проблем. Когда я тестирую, я не думаю о магнитных полях или мелких скачках напряжения, хотя они влияют на мою работу постоянно.
Многие плавающие баги никем не обнаружены просто потому, что они еще ни разу не проявились (или проявились, но никто их не заметил). Все, что мы можем сделать – это позаботиться о создании наилучшего тестового покрытия и придерживаться этого подхода. Нет в мире алгоритмов для автоматического определения или предотвращения всех плавающих багов.
Итак, то, что обычно называется плавающим багом – это загадочное, нежелательное поведение системы, которое наблюдалось как минимум единожды, и которое мы не можем спровоцировать повторно.
Наша задача – превратить плавающий баг в обычный, раскрыв тайны, окружающие его. После этого он становится головной болью программистов.
Принципы работы с плавающими багами
- Успокойтесь, они, скорее всего, не вызваны злыми духами.
- Если это случилось один раз – скорее всего, это произойдет снова.
- Если баг не был исправлен, вряд ли он самоликвидировался навсегда.
- С осторожностью относитесь к исправлениям плавающих багов. Исправленный баг и неисправленный плавающий баг неотличимы друг от друга по определению в течение какого-то времени и/или при определенных условиях.
- Любое состояние системы, переход в которое занимает длительное время в обычных обстоятельствах, может быть мгновенно достижимым в непредсказуемых ситуациях.
- Сложное и запутанное поведение обычно спровоцировано чем-то довольно простым.
- Сложное и запутанное поведение иногда спровоцировано целым комплексом причин.
- Плавающие баги зачастую могут рассказать вам много интересного про ваш продукт.
- Очень легко поддаться уверенности, что ваше предположение об источнике проблемы разумно, остроумно и имеет смысл – оно просто неверное.
- Ключ к разгадке может находиться в руках другого человека.
- Возможно, что баг, «плавающий» на тест-стенде, легко воспроизведется на проде.
- Принцип Pentium 1994: плавающая техническая проблема может привести к систематическим и очень дорогостоящим проблемам бизнеса.
- Проблема может быть плавающей, но риск, связанный с ней, стабилен.
- Чем выше тестируемость продукта, тем легче исследовать плавающие баги.
- Когда вы исключили все невозможное, то то, что осталось, каким бы невероятным оно ни было, уже нанесло существенный урон! Поэтому не ждите момента, когда вы полностью раскусите этот орешек, заводите плавающие баги как можно раньше!
- Если вы не успеваете ущучить плавающий баг до релиза, сделайте все, что в ваших силах, чтобы все-таки выловить его и исправить. Получайте удовольствие от процесса, так сказать.
Общие советы по исследованию плавающих проблем
- Перепроверьте свои базовые предположения: используете ли вы именно тот компьютер? Тестируете ли вы именно то, что нужно? Верны ли ваши наблюдения?
- Свидетельства очевидцев могут оставить за бортом важную информацию, поэтому слушайте, но не нужно излишней уверенности в чужих словах.
- Пригласите других наблюдателей, подключите к процессу большее количество людей.
- Мотивируйте людей сообщать о плавающих проблемах.
- Если вам сказали, что причина проблемы ТОЧНО не в этом, обратите на ЭТО особое внимание.
- Проверьте сайты технической поддержки каждого из сторонних компонентов, который используется в вашем приложении. Возможно, ваша проблема там указана.
- Ищите инструменты, которые помогут вам наблюдать за поведением системы и контролировать его.
- Налаживайте коммуникацию с наблюдателями (особенно с реальными пользователями).
- Соберите все загадочные баги в одном месте, чтобы легче было отслеживать закономерности.
- Просмотрите список багов, поищите в нем похожие на плавающий баг проблемы.
- Точнее зафиксируйте свои наблюдения, пользуйтесь инструментами.
- Улучшите тестируемость вашего продукта, добавьте логирование и интерфейсы с поддержкой сценариев.
- Точнее контролируйте данные, которые вы вводите (включая их последовательность, время, типы, размеры, источники, итерации, комбинации).
- Систематически покрывайте тестами данные ввода и состояния системы.
- Сохраняйте абсолютно все логи. Возможно, позже вам понадобится сравнить новые логи со старыми.
- Если проблема чаще возникает в одних ситуациях и реже – в других, проведите статистический анализ разницы между закономерностями в этих ситуациях.
- Попробуйте контролировать то, что, с вашей точки зрения, не имеет значения.
- Упрощайте все. Попытайтесь менять одну переменную за раз, попробуйте разбить систему на части (помогает понять и изолировать проблему).
- Усложняйте. Попытайтесь изменить несколько переменных за раз, устройте в системе бардак (помогает выловить «лотерейные» баги).
- Добавьте элемент случайности в состояния системы и обрабатываемые данные (возможно, при помощи менее жесткого контроля), чтобы добиться состояний, которые, возможно, не вписываются в ваш обычный шаблон использования.
- Создайте искусственный стресс (высокая нагрузка, большие объемы данных).
- Поставьте ловушку, чтобы при возникновении проблемы в следующий раз вам удалось изучить ее получше.
- Подумайте насчет код-ревью.
- Поищите конфликты между компонентами, созданными разными компаниями.
- Собирайте и храните рассказы о локализации плавающих багов.
- Систематически размышляйте о причинах плавающих багов (см. ниже).
- Опасайтесь потратить кучу времени на мелкий баг, всегда спрашивайте себя, стоит ли он того.
- Если ничего не помогает, дайте проблеме отлежаться, поработайте над чем-нибудь другим и последите, не появится ли она снова.
Возможные причины плавающих багов
Локализуя плавающий баг, поразмышляйте о типах причин, вызывающих подобные проблемы. Ниже – список эвристик, которым можно пользоваться для подобного анализа. Некоторые из причин дублируются, потому что их можно рассматривать с разных точек зрения.
Вероятная причина номер 1: Система ведет себя точно так же, как и вела. Кажущийся сбой поведения – артефакт, относящийся к вашему восприятию.
- Плохие наблюдения. Наблюдатель мог быть невнимательным — например, подвергнуться «Слепоте невнимания» – феномену, когда мозг занят чем-то еще, и человек не видит того, что находится у него прямо перед носом. Если показать ему то же самое еще раз, он увидит нечто новое для себя и предположит, что раньше такого не происходило. К тому же так работает ряд оптических иллюзий, демонстрируя кажущееся иным поведение при том, что ровным счетом ничего не изменилось.
- Наблюдения, не относящиеся к делу. Наблюдатель обращает внимание на различия, которые не имеют значения. То, что важно, остается стабильным. Это случается, когда наблюдатель чересчур пристально бдит за мелочами.
- Плохая память. Возможно, наблюдатель плохо запомнил свои впечатления, или записи, фиксирующие проблему, повреждены. Когда вы наблюдаете за чем-то, ваш мозг обрабатывает кучу данных! Он немедленно упаковывает их и пытается связать их с другими данными, при этом важная информация может потеряться. К тому же в процессе разработки и тестирования мы повторяем одно и то же довольно часто, и можем запутаться в деталях каждого отдельного наблюдения.
- Ложная атрибуция. Наблюдатель приписывает свое наблюдение не тому, чему нужно. К примеру, «Microsoft Word упал» может означать, что упала Windows, и причина падения не имеет к Word ни малейшего отношения. Word вообще ничего не делал. Этот феномен еще называют «ложной корреляцией» и часто встречается, когда одно событие следует сразу же после другого, и кажется, что это причина и следствие. Благодаря ложной корреляции плавающие баги зачастую считаются обычными багами, появившимися из-за крайне сложного и маловероятного комплекса причин.
- Искажение фактов. Наблюдатель, возможно, неверно передает информацию. Причин может быть множество – например, вполне невинная: он настолько уверен в своих предположениях, что передает свои наблюдения определенным образом. Как-то раз я спросил сына, подключена ли его нерабочая Playstation к сети. «Конечно», огрызнулся он. Попробовав решить проблему так и сяк, я решил, что блок питания умер. После чего посмотрел на него и обнаружил, что штекер не включен в розетку.
- Ненадежный оракул. Мнение наблюдателя насчет того, что является проблемой, а что нет, постоянно меняется. У нас может создаться впечатление, что проблема плавающая, только потому, что некоторые люди – иногда – не считают это поведение проблемой, даже если оно вполне предсказуемое. Другие люди могут отнестись к вопросу иначе, и даже один и тот же человек может поменять свое мнение.
- Ненадежная коммуникация. Коммуникация с наблюдателем может быть неполной. У нас создается ощущение, что мы нашли плавающий баг, потому что сообщения о нем не всегда до нас доходят, даже если проблема вполне предсказуема. Фраза «Мне кажется, проблема больше не проявляется» может означать, что люди просто перестали о ней сообщать.
Вероятная причина номер 2: Система ведет себя иначе, потому что это другая система.
- Deusexmachina. Разработчик мог специально что-то поменять, а потом вернул все назад. Это часто случается, когда над разными частями платформы одновременно работает несколько разработчиков или команд, не координируя свои действия друг с другом. Другой вариант – злонамеренные модификации приложения хакерами.
- Случайное изменение. Разработчик мог внести правки случайно. Возможно, незапланированные побочные эффекты и приводят к возникновению плавающих проблем. К тому же разработчик может ошибиться и выкатить правки на прод вместо тест-стенда.
- Другая платформа. Один из компонентов платформы мог быть заменен или переконфигурирован. Администратор или пользователь могли специально или случайно изменить что-то в компоненте, от которого зависит продукт. Частый источник таких проблем – автоматические обновления Windows, изменения в конфигурации памяти и дискового пространства.
- Проблемы железа. Может, какой-то физический компонент системы сбоит время от времени. Перебои могут быть вызваны естественными вариациями в его работе, магнитными полями, излишне высокой температурой, низким зарядом батареи, плохим обслуживанием или физическим шоком.
- Чужая система. В работу вашего приложения может вмешаться какое-нибудь еще. Например, в веб-тестировании я могу иногда получать неверные результаты из-за прокси-сервера провайдера, который загружает кэшированную версию страницы в неподходящий момент. Другие примеры такого вмешательства – это сканирование на вирусы, обновления системы, другие программы или та же самая программа, запущенная повторно.
- Проблемы кода. Может, проблема кроется в том, как написан код. Один из худших багов, созданных моими руками (худших в смысле тяжести поиска причины) возникал из-за кода в игре, который иногда перезаписывал данные в совершенно другой части программы. Из-за природы этих данных игра не падала — зато поврежденная функция передавала управление функции, которая следовала сразу за ней в памяти приложения. Мне понадобилось несколько дней (и эмулятор чипа), чтобы это понять.
- Раздвоение личности. То, что вы понимаете под системой, может на самом деле состоять из нескольких систем, мимикрирующих под единую. К примеру, я могу получать разные результаты от Google в зависимости от того, на какой сервер Гугла я попадаю. Или разные компьютеры тест-команды имеют разные версии ключевого компонента, или я опечатался в URL и случайно начал тестировать на другом сервере.
- Человеческий фактор. Возможно, за запуск части системы отвечает человек, и этот человек ведет себя по-разному.
Вероятная причина номер 3. Система ведет себя иначе, потому что находится в другом состоянии.
- Замершее условие. Решение, которое должно основываться на статусе условия, могло перестать проверять это условие, застряв в состоянии «всегда да» или «всегда нет».
- Невернаяинициализация. Одна или несколько переменных не инициализируются. В результате стартовое состояние расчетов становится зависимым от предыдущих расчетов той же или иной функции.
- Отказ в ресурсах. Критически важный файл, поток или другая переменная недоступны для системы. Это может произойти, потому что они не существуют, повреждены или заблокированы другим процессом.
- Прогрессивное повреждение данных. Система могла превратиться в бардак постепенно из-за накапливающихся мелких ошибок. Например, это может проявляться как рассинхрон временных циклов, или ошибка округления при сложных или рефлексивных расчетах.
- Прогрессивная дестабилизация. Классический пример многоэтапного отказа. Первая часть бага создает нестабильность – например, указатель массива ведет в никуда при определенных условиях, однако внешне баг никак не проявляет себя. Из-за этого невидимого сбоя система переходит ко второму этапу – к видимому сбою, который происходит позднее в комбинации с какими-то другими условиями. Увязать эти события между собой очень трудно из-за задержки между первопричиной и последствиями.
- Переполнение. Какой-либо контейнер может переполниться, провоцируя сбой или обработку исключений. В эпоху больших объемов памяти о возможности переполнения часто забывают. Даже если исключение корректно обрабатывается, сам процесс обработки, взаимодействуя с другими функциями системы, может вызвать плавающую проблему.
- Редко встречающиеся функции. Некоторые функции системы используются настолько редко, что мы про них забываем. Это обработка исключений, внутренняя сборка мусора, автосохранение, функции обслуживания. Когда они срабатывают, они могут неожиданно вступить в конфликт с другими функциями или условиями. Обращайте особое внимание на скрытые и автоматические функции.
- Другой режим или настройки. Система может работать при разнообразных режимах, и пользователь установил какой-то другой. Отличия могут быть незаметны с первого взгляда.
Вероятная причина номер 4. Система ведет себя иначе, потому что получила другие вводные данные.
- Случайный ввод. Пользвоатель мог ввести что-то или изменить ввод таким образом, что это не должно было ни на что повлиять – но все же повлияло. Это можно назвать синдромом Умного Ганса – лошади, которая периодически умудрялась решать математические задачи. В результате Оскар Пфунгст обнаружил, что лошадь реагировала на непроизвольные микродвижения своего хозяина. В своей области я как-то раз столкнулся с плавающим багом, который возникал, когда солнце проникало через мое окно и падало на оптический сенсор моей мыши. Погодные условия никак не должны были повлиять на ввод данных в приложение – однако влияли. Более распространенный пример странного поведения – баги, возникающие, когда вы используете клавиатуру, а не мышь, чтобы отдать какую-либо команду. Случайный ввод может быть невидимым глазу без специальных инструментов и рекордеров. Например, два идентичных текста в RFT-формате, один из которых сохранен через Word, а другой через Wordpad, выглядят очень похоже, но совсем не идентичны.
- Секретные границы и условия. Программа может вести себя иначе из-за скрытых границ или областей падения, которые никем не задокументированы и которых вы не ожидаете, выстраивая свою ментальную модель продукта. Как-то раз я тестировал поиск, который вел себя совершенно иначе, если количество найденных записей равнялось тысяче или пятидесяти тысячам. Я обнаружил эти скрытые границы совершенно случайно.
- Другой профиль использования. Использование приложений некоторыми пользователями может чем-то специфически отличаться. Их предположения насчет ввода ведут к другим результатам вывода. Пользователи с определенным опытом – например, программисты – могут систематически замечать (или не замечать) определенные типы поведения приложения.
- Призрачный ввод. Источником ввода может быть не пользователь, а машина. Такой ввод часто незаметен пользователю, и включает вариации из-за разных файлов, различные сигналы от периферийных устройств, или данные, поступающие по сети.
- DeusExMachina. Кто-то еще взаимодействует с продуктом в то же самое время, что и пользователь – другой тестировщик, другой пользователь, хакер.
- Дефектный ввод. Данные могли быть повреждены или перехвачены на пути к системе. Особенно это касается клиент-серверных приложений.
- Время в качестве вводных данных. Плавающие баги могут зависеть и от времени как такового. Время всегда меняется вне зависимости от того, удалось ли вам проконтролировать и зафиксировать все остальное. Когда время и дата, или временные интервалы, используются в качестве данных, баги могут проявляться только в определенное время.
- Временная лотерея. Вариации ввода, которые обычно не имеют значения, могут внезапно стать критическими в определенное время или при определенной нагрузке. От этой проблемы страдал Mars Rover – окно уязвимости в три миллисекунды, когда операция записи могла писать в защищенную часть памяти.
- Комбинационная лотерея. Вариации ввода, которые обычно не имеют значения, могут вызвать проблему, если они скомбинированы определенным образом.
Вероятная причина номер 5. Прочие причины связаны с тем, что ваша ментальная модель системы и того, что на нее влияет, неверна или неполна.
- Вы можете не знать о всех переменных, влияющих на систему.
- Вы можете не знать об источниках искажений, влияющих на ваши наблюдения.
- Вы можете не знать об инструментах, которые помогли бы вам понять систему или наблюдать за ней.
- Вы можете не знать всех границ системы и характеристик этих границ.
- В системе может вообще не быть функции, которую вы в ней предполагаете, или в нее включены дополнительные функции.
- Сложный алгоритм может периодически вести себя неожиданно – например, математический хаос, который выглядит, как отклонение от нормы.