Дома как найти баги

Как научиться искать баги — Серьезность и приоритет — Алгоритм действий — Лучшие практики — Шпаргалка

Типы багов:

  • Функциональные
  • Синтаксические
  • Логические
  • Производительности
  • Ошибки вычислений
  • Безопасности
  • Уровня модуля
  • Интеграционные баги
  • Юзабилити-баги
  • Потока управления
  • Совместимости

Функциональные

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

Могут быть самыми разнообразными, начиная с бага в простой нечасто используемой функции, типа неработающей кнопки “Связаться” где-то в углу, и до полной неработоспособности всего приложения или сайта. 

Еще пример: функция кнопки “Сохранить” заключается в том, что она сохраняет внесенные изменения в документе. Если изменения при нажатии кнопки не сохраняются, это функциональный баг.

Поиском багов этого типа занимается функциональное тестирование — отдельная важная сфера в QA (мини-гайд по ссылке).

Синтаксические баги

Ошибка в коде программы. Вероятно, самая частая ошибка, статистически. Случается обычно по невнимательности. Заключается, например, в неправильном/пропущенном символе, неправильно прописанной команде, или пропущенной скобке. 

Логические ошибки

Коварная ошибка, труднее выявляемая. Приложение выдает неправильный вывод, или вообще падает

Логические дефекты это например бесконечные циклы или некорректные переходы, допущенные разработчиком по неопытности или незнанию синтаксиса, вызывающие сложно определяемые ошибки в user flow (“маршруте пользователя по приложению” в процессе пользования им).

Бесконечные циклы — больное место тестировщика, так же как утечки памяти, проблемы с типами данных во многих языках, с компилятором в С++ или сборщиком мусора в Java. Несоблюдение хороших практик в программировании и недостаток опыта у разработчиков добавляют задач QA-отделу.

Еще примеры: переменной присвоено некорректное значение; деление чисел вместо умножения, и т.п.

Подробнее о логических ошибках.

Проблемы производительности

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

Ошибки вычислений

Когда приложение выдает некорректное значение пользователю или другой программе.

  • Когда в приложении применен некорректный, неподходящий алгоритм
  • Несоответствие типа данных

Уязвимости в безопасности

Дефекты в системе безопасности, видимо, наиболее опасные из тех, с которыми сталкивается junior QA. Они “компроментируют” весь проект, всю компанию, и разумеется, QA-команду, если она их пропустила. 

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

Самыми частыми, статистически, ошибками безопасности являются: ошибки шифрования; подверженность SQL-инъекциям; XSS-уязвимости; переполнения буфера; логические ошибки в подсистеме безопасности; некорректная аутентификация.

Баги уровня модуля

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

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

Интеграционные баги

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

Становятся заметны они, когда например два (или больше) модулей кода ошибочно взаимодействуют, из-за программной несовместимости между ними. Такие баги довольно сложно определить и пофиксить, разработчикам, как правило, приходится переписывать довольно большие объемы кода.

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

Юзабилити-баги

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

Баги потока управления (Control Flow)

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

Пример: в опроснике пользователь нажимает “Сохранить”, предполагается переход к концу опросника/теста, а перехода к следующей странице не происходит. 

Проблемы совместимости (Compatibility issues)

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

Итак, уже примерно знаем, ЧТО искать, постараемся понять, КАК искать.

Как научиться искать баги

“Быстрая проверка” на реальных устройствах и в браузерах

Трудно идет тестирование, если у тестировщика нет сформулированных требований к софту — потому что трудно написать тестовые сценарии. В такой ситуации можно “атаковать систему”, вводя неправильные значения во все возможные поля. Если баги есть, они обычно проявляются.

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

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

Даже если таким образом будет найдено сравнительно мало багов, логично предположить, что все-таки есть проблемы в основной части функциональности. Отсутствие багов при “экспресс-анализе” (“quick attack”) обычно показывает, что основная часть функциональности более-менее в порядке.

Такая “быстрая атака” должна выполняться в стандартном пользовательском окружении — как можно более близком к тем условиям, в которых будет работать конечный пользователь. 

Внимание тестовому окружению

Обычно у тестировщиков есть время на подготовку сценариев, прописывание таймлайна и настройку процедур. А также на подготовку тестовой инфраструктуры, или тестового окружения

Из-за проблем с плохо подготовленным тестовым окружением возникают задержки в получении результатов тестирования. Проявляются баги, вызванные именно тестовым окружением, а не самим софтом. Мало что так раздражает, как некорректно работающее окружение.

Например, тестировщик нашел и отрепортил баг, а когда разработчик проверил его, в коде проблем не нашел, потому что проблема была с окружением. От этого возникает задержка.

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

Тщательное исследование

Перед началом тестирования нужно внимательно изучить приложение или тестируемый модуль.

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

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

Принцип Парето

Согласно этому принципу, 20% усилий дают 80% результата. 

А 80% усилий дают лишь 20% результата. 

Применительно к QA-индустрии, принцип Парето гласит, что 80% багов сосредоточены в 20% модулей. (Необязательно такое точное соотношение, но в целом). По принципу Парето, большинство багов затаились в одном-двух модулях (или даже еще меньшей части кода).

Если всерьез взяться за эти модули и вычистить из них баги, можно считать работу на 80% сделанной.

Подробно о принципе Парето в тестировании.

Четкие цели

Тестировщик должен учитывать стандарты и лучшие практики и придерживаться их, это даст понимание, какие ошибки искать тщательнее и в первую очередь. Должен понимать логику действий конечного пользователя. Что пользователь ожидает от этого софта? Какой его user experience? Какой функциональности ожидает? На какие баги вообще не обратит внимания, а какие заставят отказаться от приложения?

Четче изложенные цели тестирования помогут писать хорошие тестовые сценарии и тест-кейсы. Если главная функция, “главная потребность пользователя” уточнена и дан приоритет, тестировщик может сначала протестировать эту функцию, а остальные отложить, или поручить стажерам.

Серьезность и приоритет

По серьезности (Severity)

  • Блокирующий баг, так называемый “блокер”, который делает абсолютно невозможной дальнейшую работу с приложением. Срочно исправляют.
  • Критический баг. “Критикал”. Некорректно работает все приложение, или его важнейший модуль. Тестирование остальных, менее существенных багов прекращается, все силы бросают на фикс такого бага. Сюда входит, например, кейс, когда приложение выдает ошибку сервера при попытке входа в приложение.
  • Существенный. “Мажор”. Влияет на ключевую функцию, и приложение ведет себя с отклонением от прописанных требований. Например, email-провайдер не дает добавить больше одного адреса в поле получателя.
  • Средней серьезности. “Минор”. Когда не очень важная функция не ведет себя соответственно требованиям. Например, ссылка в “Условиях использования” продукта ведет в никуда.

(Перечисленные выше баги коротко обозначаются S1, S2, S3, S4 по серьезности.)

  • Низкой серьезности. “Тривиал”. Обычно это небольшие дефекты пользовательского интерфейса. Например, кнопки, которые должны быть одинаковыми, немножко отличаются по цвету и размеру.

По приоритету

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

Приоритеты выставляются менеджером проекта:

Высокий приоритет. Это ошибки, которые должны быть устранены до релиза, согласно критериям завершения тестирования (exit-criteria). Например, это ошибка, несмотря на корректность всех введенных данных мешающая переходу со страницы входа на главную.

Средний приоритет. Должны быть устранены до релиза или сразу после релиза. Это например дефект, не нарушающий требования, но некорректно отображающий контент в одном из браузеров.

Низкий приоритет. Их можно не фиксить, и критериям завершения это не противоречит, но такие дефекты надо устранить до финального релиза. Обычно это опечатки, небольшие дефекты в дизайне (например выравнивание текста), не очень заметные ошибки в размере элементов, и прочие “косметические” дефекты.

(Перечисленные выше баги обозначаются P1, P2, P3 от высокого к низкому.)

Также баги классифицируют по частоте проявления, от высокой до очень низкой (4 степени).

Подробнее о серьезности и приоритете, а также о глобальном приоритете и частоте багов.

Стандартный порядок действий при обнаружении бага

  1. Проверить дополнительные (связанные) вещи

Обычно баги “по одному не ходят”, то есть где-то поблизости есть аналогичные, или связанные с уже найденными. 

  1. Зафиксировать текущее состояние приложения

Состояние приложения и состояние окружения. Это поможет примерно определить причину бага — внутренняя или внешняя, и воспроизвести баг.

  1. Проверить, может баг уже есть в репортах

Чтобы не делать уже сделанную кем-то работу.

  1. Репорт

Теперь надо написать классный баг-репорт, не затягивая время — это сокращает цикл фидбека между написанием кода и валидацией.

Статусы багов (в жизненном цикле)

  • Открыт (добавлен в репорт)
  • В работе (принят к исправлению)
  • Исправлен (и передан на перепроверку)
  • Закрыт (уже не воспроизводится)

также дополнительно:

  • Отклонен (ошибка в репорте)
  • Отсрочен (как неприоритетный)
  • Переоткрыт (после двух предыдущих статусов)

Подробнее о системах контроля багов — здесь

Лучшие практики

  • Сначала хорошо исследовать и понять приложение (модуль)
  • Создать специальные тест-кейсы, а именно функциональные тест-кейсы, посвященные критически важным функциям
  • Подготовить достаточно тестовых данных
  • Запустить тесты снова, в другом тестовом окружении
  • Сравнивать полученные результаты с ожидаемыми
  • Проанализировать тестовый сет, используя старые тестовые данные
  • Выполнить стандартные тест-кейсы, которые ранее показывали себя надежными. Например, если тестировалось поле ввода для стандартного текста, ввести HTML-теги и проверить, что получится
  • После завершения большей части тестов, если есть усталость, отдохнуть, занявшись обезьяньим тестированием (monkey testing)

Тестирование на реальных девайсах и в реальных окружениях

Тестирование в реальных окружениях является хорошей практикой в QA, а в тестировании мобильных приложений — обязательной практикой. Реальное окружение быстрее “апгрейдит” тестировщика. Но оно требует закупки/аренды довольно-таки внушительного парка устройств. Вообще, тестирование всех возможных комбинаций браузер/ОС/девайс — отдельная головная боль. Здесь помогают облачные платформы.

***

Шпаргалка QA Trainee/Junior

Серьезность бага

  • Blocker
  • Critical
  • Major
  • Minor
  • Trivial

Приоритет

  • Top
  • High
  • Normal
  • Low

Типы багов

  • Функциональные
  • Синтаксические
  • Логические
  • Производительности
  • Ошибки вычислений
  • Безопасности
  • Уровня модуля
  • Интеграционные баги
  • Юзабилити-баги
  • Потока управления
  • Совместимости

Частота бага

  • Высокая
  • Средняя
  • Низкая
  • Очень низкая

Статус бага

  • Открыт
  • В работе
  • Исправлен
  • Закрыт
  • Отклонен
  • Отсрочен
  • Переоткрыт

Что делает тестировщик, когда находит баг

  • Проверяет связанные или аналогичные вещи
  • Фиксирует текущее состояние приложения и тестового окружения
  • Проверяет, нет ли этого бага в репорте
  • Пишет репорт

***

Пять технических и пять нетехнических навыков хорошего QA

 Регрессионное тестирование: подборка инструментов

Эмуляторы и симуляторы: в чем разница

Как искать баги начинающему тестировщику?

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

Сфокусируйтесь на одном деле

Сосредоточьтесь на мысли «где-то тут спрятались баги, и я их непременно отыщу». Баги всегда есть, и вы их найдёте.

Ничего не пропускайте

Даже если обнаруженный вами баг кажется незначительным не стоит его пропускать, а лучше сразу задокументировать. Если у вас есть мысли как лучше сделать, то сразу задокументируйте это пока ещё не забыли. Так вы пополните список найденных вами багов.

Выделите время только для работы

Выделите по часу в день – когда вы возьмете кофе/какао/чаёк оденете наушники и сосредоточьтесь на поиске багов.

Также важно помнить, что это нужно делать постоянно.

Учите теорию

Как искать баги начинающему тестировщику?

Огромное количество полезной информации уже давно есть в книгах и на просторах интернета.

Вам следует уделить должное внимание этой информации ведь то что ещё 10 лет назад можно было узнать в процессе работы сейчас обязательно спросят на собеседовании.

Не тестируйте одно и тоже

Не следует ограничивать себя чем-то одним. Тестируйте сайты автосалонов, интернет магазинов, мобильные приложения и т.д.

Так вы быстрее поймете какие баги встречаются часто и как их находить.

Обращайтесь с тестировщиками

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

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

Не делайте одно и тоже

Отметьте проверенное и сфокусируйтесь на поэтапном тестировании того что ещё не проверили. Периодически переключайтесь между областями проекта и методами проведения тестов. Если вы уже давно занимаетесь тестированием скажем 2-3 года тогда-то подумайте о том, чтобы заняться нагрузочным тестированием или тест дизайном. Дайте вашему сознанию посмотреть на ваши обычные задачи под другим углом.

Автоматизируйте

Как искать баги начинающему тестировщику?

Многие тестировщики каждый день повторяют одни и те же рутинные действия. Если это про вас, то или же вы уже давно подумываете над тем чтобы что-то автоматизировать из вашей ежедневной работы – сделайте это.

Мы зацикливаемся на повторяющихся действиях именно из-за ним мы и теряя концентрацию. А для того чтобы находить баги вы должны быть сосредоточены. Старайтесь всегда поддерживать концентрацию ни на что, не отвлекаясь.

Ищите подсказки у пользователей и разработчиков

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

Специалисты AskerWeb вам всегда рады! Обращайтесь по номеру +375291593474 или переходите на наш сайт Askerweb.by.

#баг, #искать баги, #баги #поискамибагов , #тестировании, #тестов, #тестируйте

Содержание

1. СФОКУСИРУЙТЕСЬ НА ОДНОМ ДЕЛЕ
2. НИЧЕГО НЕ ПРОПУСКАЙТЕ
3. ВЫДЕЛИТЕ ВРЕМЯ ТОЛЬКО ДЛЯ РАБОТЫ
4. УЧИТЕ ТЕОРИЮ
5. НЕ ТЕСТИРУЙТЕ ОДНО И ТОЖЕ
6. ОБРАЩАЙТЕСЬ С ТЕСТИРОВЩИКАМИ
7. НЕ ДЕЛАЙТЕ ОДНО И ТОЖЕ
8. АВТОМАТИЗИРУЙТЕ
9. ИЩИТЕ ПОДСКАЗКИ У ПОЛЬЗОВАТЕЛЕЙ И РАЗРАБОТЧИКОВ

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

Сфокусируйтесь на одном деле

Сосредоточьтесь на мысли «где-то тут спрятались баги, и я их непременно отыщу». Баги всегда есть, и вы их найдёте.

Ничего не пропускайте

Даже если обнаруженный вами баг кажется незначительным не стоит его пропускать, а лучше сразу задокументировать. Если у вас есть мысли как лучше сделать, то сразу задокументируйте это пока ещё не забыли. Так вы пополните список найденных вами багов.

Выделите время только для работы

Выделите по часу в день – когда вы возьмете кофе/какао/чаёк оденете наушники и сосредоточьтесь на поиске багов.

Также важно помнить, что это нужно делать постоянно.

Учите теорию

Огромное количество полезной информации уже давно есть в книгах и на просторах интернета.

Вам следует уделить должное внимание этой информации ведь то что ещё 10 лет назад можно было узнать в процессе работы сейчас обязательно спросят на собеседовании.

Не тестируйте одно и тоже

Не следует ограничивать себя чем-то одним. Тестируйте сайты автосалонов, интернет магазинов, мобильные приложения и т.д.

Так вы быстрее поймете какие баги встречаются часто и как их находить.

Обращайтесь с тестировщиками

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

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

Не делайте одно и тоже

Отметьте проверенное и сфокусируйтесь на поэтапном тестировании того что ещё не проверили. Периодически переключайтесь между областями проекта и методами проведения тестов. Если вы уже давно занимаетесь тестированием скажем 2-3 года тогда-то подумайте о том, чтобы заняться нагрузочным тестированием или тест дизайном. Дайте вашему сознанию посмотреть на ваши обычные задачи под другим углом.

Автоматизируйте

Многие тестировщики каждый день повторяют одни и те же рутинные действия. Если это про вас, то или же вы уже давно подумываете над тем чтобы что-то автоматизировать из вашей ежедневной работы – сделайте это.

Мы зацикливаемся на повторяющихся действиях именно из-за ним мы и теряя концентрацию. А для того чтобы находить баги вы должны быть сосредоточены. Старайтесь всегда поддерживать концентрацию ни на что, не отвлекаясь.    

Ищите подсказки у пользователей и разработчиков

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

Где искать баги фаззингом и откуда вообще появился этот метод

Время на прочтение
8 мин

Количество просмотров 6K

Подход фаззинг-тестирования родился еще в 80-х годах прошлого века. В некоторых языках он используется давно и плодотворно — соответственно, уже успел занять свою нишу. Сторонние фаззеры для Go были доступны и ранее, но в Go 1.18 появился стандартный. Мы в «Лаборатории Касперского» уже успели его пощупать и тестируем с его помощью довольно большой самостоятельный сервис.

Меня зовут Владимир Романько, я — Development Team Lead, и именно моя команда фаззит баги на Go. В этой статье я расскажу про историю фаззинга, про то, где и как искать баги, а также как помочь фаззинг-тестам эффективнее находить их в самых неожиданных местах. И покажу этот подход на примере обнаружения SQL-инъекций.

Немного истории

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

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

Так что же произошло?

Тем ученым был Бартон Миллер. В 1988 году он работал профессором в университете и решил из дома подключиться через модем к своему любимому университетскому мейнфрейму. Он пытался выполнить команду Unix… История умалчивает о том, какая именно это была команда. Предположим, это был grep.

grep -R "hello world"

В этот момент где-то недалеко ударила молния. А старый модем если и имел код коррекции ошибок, тот оказался недостаточно эффективным. Вместо «Hello world» до мейнфрейма долетел мусор:

grep -R "hello ~3#зеШwкACh"

Который внезапно вызвал segmentation fault. И grep упал.

Бартон Миллер задумался, почему это произошло. Grep к тому времени уже был старой, надежной, многократно протестированной командой, у которой явно есть какие-то проверки ввода. Но тем не менее он упал. И ученому пришла в голову идея написать программу, которая специально будет генерировать мусор и отправлять на вход в различные unix-овые утилиты. Так появился первый фаззер.

Вместе со студентами Бартон Миллер нашел очень много ошибок в командах Unix. К этому моменту все эти команды уже использовались инженерами по всему миру в течение длительного времени, но тем не менее содержали ошибки. Такова суперспособность фаззера, за которую мы его и любим, — находить баги в хорошо протестированном коде.

Как фаззер находит баги

Тесты можно классифицировать по-разному. Но давайте распределим их по уровню семантического знания о коде, которое использовано при написании теста.

Больше всего знаний о тестируемом коде используется при построении тестов по тест-кейсам, например в юнит-, ручных или интеграционных тестах. Они содержат некие пред- и постусловия — конкретные проверки того, что на вход программы мы передали А, а на выходе должны получить Б. Для написания таких тестов однозначно придется изучить код и требования к нему.

Левее по этой шкале находятся property based тесты. В них уже нет конкретных входов и выходов. Данные на вход генерируются случайным образом, но проверяются определенные свойства кода (поэтому тесты и называются property based). К примеру, если мы проверяем функцию сортировки, на выходе ожидаем массив, каждый последующий элемент которого больше либо равен предыдущему.

В крайней левой части шкалы находятся фаззинг-тесты, имеющие минимальные знания о продукте. Им известно только то, что код не должен падать, зависать или отъедать какое-то безумное количество памяти. С точки зрения теста сам продукт представляет собой черный ящик.

В том, что при фаззинге используются минимальные знания, есть как плюсы, так и минусы. Если тесты по тест-кейсам позволяют находить так называемые known unknowns (т. е. проверяют неизвестное поведение в известных сценариях), то фаззинг ищет unknown unknowns (проверяет неизвестное поведение в неизвестных сценариях). Именно эта особенность позволяет фаззингу находить баги в хорошо протестированном коде — он обнаруживает сценарии, про которые разработчик никогда и не подумал бы.

Для примера приведу тесты для функции сортировки, которая принимает слайс int.

Функцию можно протестировать с помощью тестов по тест-кейсам. В этом случае на вход мы передаем (2, 1, 3) и проверяем ожидание, что на выходе будет 1, 2, 3.

В property based тестах на входе случайная последовательность, а на выходе надо убедиться, что каждый последующий элемент больше или равен предыдущему (т. е. проверяется свойство).

Фаззинг также передаст случайную последовательность, но удостоверится, что функция не упала.

Фаззинг не заменяет классическое тестирование. Он нужен, когда проверяется уже оттестированный код, а фантазия тестировщиков подходит к концу. В общем случае фаззер найдет меньше ошибок, чем тесты по тест-кейсам. Но эти ошибки будут наиболее разнообразны. Это хорошо заметно в Go-шной реализации фаззера — go fuzz, которая модифицирует корпус входных тестовых данных так, чтобы отработали все ветви кода. Стандартный фаззер Go вообще одинаково хорошо подходит как для написания property based тестов, так и для классического фаззинга. Официальная документация Go по фаззингу не делает различия между этими видами тестов.

Как помочь фаззеру

Давайте рассмотрим нехитрую программу на Go.

Наш код объявляет неинициализированный нулевой указатель и что-то по нему пишет.

Если запустить этот код, он упадет с ошибкой. Проблема в пятой строке.

Чисто теоретически ее можно было бы проигнорировать и продолжить выполнение. Если кто-то помнит, в Visual Basic был такой режим: при ошибке программа не падала, а просто переходила к следующей строке кода. Получалось, что они надежны, но поведение этих программ непредсказуемо. Это никак не помогло бы фаззеру.

Вернемся к Бартону Миллеру. Что было бы, если бы grep проигнорировал обращение к невалидному указателю? Скорее всего, фаззер не нашел бы багов в команде. Команда обработала бы мусор на входе и выдала мусор на выходе. Никто не понял бы, что произошло нечто плохое. Т. е. фаззер в принципе смог найти ошибку только благодаря крэшу (программа проверила свой собственный внутренний инвариант, согласно которому нельзя обращаться к некорректному указателю, и упала, когда он оказался нарушен).

Так мы приходим к выводу: падать с ошибкой полезно.

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

Вот несколько примеров с проверкой внутренних инвариантов:

  • Инвариант может заключаться в том, что оба потомка красного узла в красно-черном дереве — черные. Если он нарушен, код может как-то сообщить об этом фаззеру.
  • Можно проверять, что количество элементов в контейнере неотрицательно — в очереди не может содержаться «-1» элемент.
  • Проверка может выявлять, что в стеке количество операций Pop меньше или равно количеству Push.
  • Бизнес-логика может контролировать отсутствие превышения некоего программного лимита. Тот факт, что мы обнаружим нарушение этого инварианта, будет свидетельствовать об ошибке в бизнес-логике.
  • Кэш должен отсекать повторные запросы. Это особенно актуально, если база вычисляет тяжелые запросы и нужно проверить бизнес-логику, которая хранит в памяти результаты нескольких последних запросов. В этом случае фаззер может найти ошибку в логике работы с кэшем.
  • SQL-запрос не должен возвращать ошибку некорректного синтаксиса. Если же мы получаем такую ошибку, в нашем коде однозначно есть проблема. Скорее всего, мы неправильно формируем тело SQL-запроса или в это тело без какой-либо санитизации попадает пользовательский ввод (SQL-инъекция).

Все эти примеры объединяет тот факт, что если проверка сработает, это однозначно указывает на некорректно написанный код. Это никак не связано с окружением. По сути это ничем не отличается от обращения к невалидному указателю, упомянутому выше.

Инвариант мало проверить, нужно еще донести до фаззера информацию о том, что есть нарушение. Самый простой способ — кинуть panic. Это можно сделать с любого уровня абстракции.

Среди Go-феров есть предубеждение против panic, поэтому можно использовать более лайтовые варианты:

  • Кидать panic не всегда, а только в специальном фаззинг-режиме: ввести переменную окружения, и если она задана, при нарушении инвариантов кидать panic. Фаззинг-режим, кстати, помогает решить проблему с «дорогими» проверками инвариантов, когда на них уходит много ресурсов.
  • Можно использовать специальный уровень логирования, доступный фаззеру. Когда тот увидит запись с этим уровнем, он поймет, что нарушен некий внутренний инвариант (и сделает вывод, что код написан некорректно). Этот подход требует более сложной инфраструктуры. И важно не писать в лог на этом уровне, когда наблюдаются проблемы с инфраструктурой (например, если отвалилась сеть).

При проверке инвариантов у фаззинг-теста нет никакого ожидания относительно кода. За счет этого он более стабильный — его не нужно менять при малейших изменениях. С развитием продукта его также нужно поддерживать, но усилий на это будет уходить гораздо меньше, чем в случае с тестами по тест-кейсам. Возвращаясь к примеру с grep — если мы сменим движок обработки регулярных выражений, суть теста никак не изменится.

Фаззинг имеет смысл, если функции работают достаточно быстро. Если функция выдает ответ через несколько минут после передачи в нее начальных данных, за разумное время фаззер просто не успеет ничего проверить. А проверив слишком мало вариантов, он ничего не найдет. Возможно, в этой ситуации процесс ускорят моки, но работать с ними надо всегда очень осторожно. Также можно гонять тесты на маленьких частях кода.

Помогаем фаззеру искать SQL-уязвимости

Теперь применим этот подход, чтобы обрабатывать ошибки работы с базой данных на примере SQLite.

Предположим, у нас есть нативный код, в котором присутствует уязвимость SQL-инъекции. Мы формируем строку, и если получаем ошибку, смотрим, что это было. Если это ошибка SQLite, которая говорит, что синтаксис некорректный, и при этом включена переменная окружения FUZZING, мы кидаем panic. В ином случае мы обрабатываем ошибки стандартным путем.

Каждый раз писать такой код неудобно, поэтому его можно разбить на вспомогательные функции и уже их использовать по всему коду.

Я бы предложил такой вариант разбиения.

Мы выделяем функцию ProcessCriticalErr, которая на вход принимает критическую ошибку (в нашем случае — нарушение синтаксиса) и кидает panic, если выставлена переменная окружения. Когда переменная окружения не выставлена, она просто возвращает ошибку.

Дополнительно нам потребуется функция, которая определяет, является ли данная ошибка критической. У SQLite есть несколько кодов ошибок, подходящих под нашу ситуацию.

Третья функция — также вспомогательная. Она принимает на вход ошибку базы данных, проверяет ее «критичность» и при необходимости вызывает процедуру обработки таких ошибок.

В этом случае наша стандартная функция работы с базой данных упрощается до такого вида:

При обнаружении критической ошибки в фаззинг=-режиме мы сообщаем об этом фаззеру, который и запоминает, что подобрал входные данные, ломающие внутреннюю логику. В данном случае фаззер помогает найти SQL-инъекцию.

Напоследок я бы рекомендовал ознакомиться с двумя ссылками:

  • https://go.dev/doc/tutorial/fuzz — о том, как вообще пользоваться фаззингом в Go, конкретно go fuzz. Он подходит для написания как классических фаззинг- тестов, о которых я рассказывал, так и для property based тестов.
  • https://www.fuzzingbook.org/ — очень полезный сайт, который посвящен фаззингу в целом. Это отдельный большой мир с огромным количеством способов разработки таких тестов. Рекомендую ознакомиться с информацией, которая есть на этом сайте. Если фаззинг применять «в лоб», он просто будет нагревать поверхность нашей атмосферы. Чтобы он находил баги, требуется включать голову, и этот ресурс подскажет, в каком направлении думать. Нужно просто научиться замечать в коде возможности для написания фаззинг-теста.

В нашей команде мы пока только пробуем стандартный фаззинг Go, но уже тестируем с его помощью довольно большой самостоятельный сервис конвертации данных из различных источников к стандартизированному виду. Для ускорения работы мы убрали из фаззинга работу с сетью и очередями, оставив только внутренности сервиса. Приходите к нам в разработку на Go — сможете пощупать все это своими руками. Тем более, у нас не надо доказывать руководству необходимость применения подобных методик. А в том, что касается фаззинга, он еще и регламентируется нормативными документами, если уж мы хотим сертифицировать свой код для каких-либо целей.

Создатель сайта Ольга Назина (ранее Киселева) подготовила статью в помощь студентам своего тренинга, описав методику систематического поиска багов по Джеймсу Уиттакеру (James A. Whittaker)

Методика туров

Приложение — незнакомый город.
Тестировщик — турист.

Исследуйте ПО так, словно это — незнакомый город

Исследуйте ПО так, словно это — незнакомый город

У туриста мало времени, поэтому он выполняет конкретную задачу, ни на что другое не отвлекаясь. Он бегает по казино, или осматривает достопримечательности, или посещает деловой семинар. Что угодно, но что-то одно.

Как пользоваться методикой

Выбрать тур из списка ниже.
Изучить его цели.
Поставить таймер на 2 часа (час, полчаса).
Провести исследование системы строго по целям тура. Ни на что не отвлекаясь, только “миссия” тура.
При необходимости повторить.

В каждом туре есть описание автора (низкий поклон Джеймсу за разрешение перевода и публикации) в вольном переводе + собственные примеры. Для примеров взят сайт Дадаты — https://dadata.ru.

Отправляемся в путь!

Туры по деловому центру, Tours of the Business District

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

При исследовании ПО все наоборот. Деловой центр — это те функции, ради которых пользователи покупают и используют приложение. Это те killer-feature, которые описывают маркетологи, и которые упомянет любой из ваших пользователей при опросе, зачем им ваше приложение.

Тур по деловому центру фокусирует внимание на главных частях вашего приложения и показывает сценарии их использования вашими клиентами.

Тур по путеводителю. The Guidebook Tour

Денежный тур. The Money Tour

Тур по ориентирам. The Landmark Tour

Интеллектуальный тур. The Intellectual Tour

The FedEx Tour

Внеурочный тур. The After-Hour Tour

Сборщик мусора. The Garbage Collector Tour

Туры по историческим районам, Tours Through the Historical District

Исторические районы — части города, содержащие старые здания и достопримечательности. В Бостоне они разбросаны по всему городу и соединены только пешеходными тропами. В Кёльне есть «старый город» — одна часть города, которая не тронута современной экспансией.

В ПО исторические районы могут быть также слабо соединены, как в Бостоне или сосредоточены в одном месте, как в Кёльне. Исторические районы в ПО представляют собой:

  • унаследованный код (legacy code);
  • функции, созданные в предыдущих версиях;
  • исправления багов.

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

Туры по историческим районам проверяют старую функциональность и исправления ошибок.

Тур по плохому району. The Bad-Neighborhood Tour

Музейный тур. The Museum Tour

Тур предыдущей версии. The Prior Version Tour

Туры по развлекательным районам, Tours Through the Entertainment District

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

В большинстве приложений есть сходные функции. Например, деловой район для текстового редактора — набор функций для создания документа, подготовки текста, вставки графики, таблиц и рисунков. Развлекательный район — функции для разметки страницы, форматирования, изменения фона. Другими словами, работа заключается в создании документа, а развлечение — в наведении красоты.

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

Тур актера второго плана. The Supporting Actor Tour

Тур глухого переулка. The Back Alley Tour

Тур полуночника. The All-Nighter Tour 

Тур чашки кофе

Туры по туристическим районам, Tours Through the Tourist District

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

Туры по туристическим районам имеют несколько разновидностей. Это и короткие забеги для покупки сувениров, аналог кратких тест-кейсов для тестирования специфичных функций. Это и длинные поездки для посещения списка мест, которые хочется увидеть. Эти туры не о том, как заставить приложение работать, они о том, как посетить функциональность быстро… только чтобы сказать “мы тут были”!

Тур коллекционера. The Collector`s Tour

Тур одинокого бизнесмена. The Lonely Businessman Tour

Тур супермодели. The Supermodel Tour

Тур «Второй бесплатно». The TOGOF Tour

Тур шотландского паба. The Scottish Pub Tour

Туры по отельным районам, Tours Through the Hotel District

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

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

Тур, отмененный из-за дождя. The Rained-Out Tour

Тур домоседа. The Couch Potato Tour

Туры по захудалым районам, Tours Through the Seedy District

Это непривлекательные места, о которых расскажет редкий путеводитель. Они полны мошенников и сомнительных личностей, и лучше обходить их стороной. Тем не менее, они привлекают определенный класс туристов.

Тур саботажника. The Saboteur Tour

Тур антисоциального типа. The Antisocial Tour

Обсессивно-компульсивный тур, или тур невротика. The Obsessive-Compulsive Tour (Тур Шелдона)

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

Туры от других авторов

Тур от моей студентки — для тестирования мобильного ПО

Тур по метро. The Metro Tour

**************

Большое спасибо Джеймсу Уиттакеру за разрешение на перевод и публикацию туров. Туры также опубликованы в блог-посте Ольги Назиной, и добавлены в ее книгу!

Добавить комментарий