1. Жизненный цикл тестирования и виды тестов
Жизненный цикл тестирования и виды тестов
Представьте, что вы строите мост. Вы не будете ждать окончания строительства, чтобы пустить по нему колонну тяжелых грузовиков и посмотреть, выдержит ли конструкция. Инженеры проверяют качество бетона еще на заводе, затем тестируют отдельные опоры, оценивают прочность соединений и только потом проводят финальные испытания всей конструкции.
В разработке программного обеспечения действует тот же принцип. Тестирование программного обеспечения — это систематический процесс проверки приложения на соответствие заданным требованиям. Его главная цель — найти ошибки (баги) до того, как продукт попадет к пользователю.
Зачем это нужно знать разработчику? Ошибка, найденная на этапе написания кода, стоит копейки: программист просто стирает строку и пишет новую. Ошибка, найденная после релиза, может стоить компании миллионов. Например, если в интернет-магазине сломается кнопка «Оплатить», при потоке в 1000 клиентов в час со средним чеком 5000 руб., компания будет терять 5 000 000 руб. каждый час простоя.
Жизненный цикл тестирования (STLC)
Многие новички думают, что тестирование — это хаотичное «прокликивание» готовой программы. На самом деле это строгий инженерный процесс, который идет параллельно с написанием кода. Этот процесс называется жизненным циклом тестирования (Software Testing Life Cycle, STLC).
STLC состоит из шести последовательных этапов. Пропуск любого из них неизбежно ведет к снижению качества продукта.
1. Анализ требований
На этом этапе команда изучает, что именно должна делать программа. Тестировщики и разработчики читают документацию и задают вопросы бизнесу. Главная задача здесь — убедиться, что требования логичны, полны и не противоречат друг другу.> Требование: «Пароль пользователя должен быть безопасным». > Это плохое требование, потому что понятие «безопасный» субъективно. Хорошее требование: «Пароль должен состоять минимум из 8 символов, содержать хотя бы одну заглавную букву и одну цифру».
2. Планирование тестирования
Команда определяет стратегию: что мы будем тестировать, какие инструменты использовать (например, библиотеку pytest для Python), сколько времени это займет и кто будет за это отвечать. Результатом этого этапа становится документ — тест-план.3. Тест-дизайн
Это этап проектирования проверок. Специалисты создают тест-кейсы — пошаговые инструкции, описывающие, что нужно сделать, какие данные ввести и какой результат ожидается.Например, для функции деления двух чисел и тест-кейсы будут такими:
4. Настройка тестовой среды
Программу нельзя тестировать там же, где ее пишут разработчики, или там, где ею пользуются реальные клиенты. Для проверок создается отдельная изолированная среда — сервер с нужной версией операционной системы, базой данных и тестовыми (ненастоящими) пользователями.5. Выполнение тестов
Только на пятом этапе начинается фактическая проверка кода. Тесты запускаются вручную или автоматически. Если фактический результат работы программы не совпадает с ожидаемым (из тест-кейса), заводится баг-репорт — отчет об ошибке, который отправляется разработчику на исправление.6. Завершение тестирования
Когда все тесты пройдены, а критические ошибки исправлены, команда собирает метрики. Одной из важных метрик является покрытие кода тестами. Оно рассчитывается по формуле:Где:
Если из 1000 строк кода тесты проверили 850, покрытие составит 85%.
!Схема жизненного цикла тестирования (STLC)
Пирамида тестирования и виды тестов
Программы состоят из множества слоев: от крошечных функций до сложных пользовательских интерфейсов. Проверять все это одним способом неэффективно. В индустрии принята концепция пирамиды тестирования, которая делит тесты на три основных уровня.
Юнит-тестирование (Модульное тестирование)
Это фундамент пирамиды. Юнит-тесты проверяют самые мелкие, изолированные части кода — отдельные функции или методы классов. Они пишутся самими разработчиками и выполняются за миллисекунды.Зачем это нужно: юнит-тесты локализуют ошибку. Если тест упал, вы точно знаете, в какой именно функции проблема, и вам не нужно искать баг по всему проекту.
Рассмотрим пример на Python. У нас есть простая функция расчета итоговой стоимости товара с учетом скидки:
Юнит-тест для этой функции будет выглядеть так:
В этом тесте мы проверяем только математику внутри одной конкретной функции. Мы не подключаемся к базе данных и не открываем браузер.
Интеграционное тестирование
Когда отдельные функции (юниты) проверены и работают правильно, их нужно объединить. Интеграционные тесты проверяют, как различные модули системы взаимодействуют друг с другом или с внешними сервисами (базами данных, сторонними API).Зачем это нужно: две функции могут идеально работать по отдельности, но при попытке передать данные из одной в другую произойдет сбой из-за несовпадения форматов.
Пример из жизни: вы купили отличный японский телевизор (юнит 1) и отличную европейскую игровую приставку (юнит 2). По отдельности они исправны. Но когда вы пытаетесь подключить приставку к телевизору, выясняется, что у них разные стандарты вилок для розетки. Это ошибка интеграции.
В коде интеграционный тест может проверять, правильно ли функция сохранения пользователя записывает данные в реальную базу данных PostgreSQL.
Функциональное тестирование (End-to-End)
На вершине пирамиды находятся тесты, которые проверяют систему целиком, имитируя действия реального пользователя. Это сквозное тестирование (End-to-End, E2E).Зачем это нужно: бизнесу не так важно, как работают отдельные функции в коде. Бизнесу важно, чтобы клиент мог зайти на сайт, положить товар в корзину и оплатить его.
При функциональном тестировании веб-приложения специальная программа (например, Selenium или Playwright) открывает настоящий браузер, кликает по кнопкам, заполняет формы и проверяет, появилось ли на экране сообщение об успешной оплате. Такие тесты пишутся долго, выполняются медленно и требуют сложной настройки среды, поэтому их должно быть меньше всего в проекте.
| Характеристика | Юнит-тесты | Интеграционные тесты | Функциональные (E2E) | | :--- | :--- | :--- | :--- | | Что проверяют | Отдельные функции | Связи между модулями | Весь путь пользователя | | Скорость выполнения | Миллисекунды | Секунды | Минуты | | Кто пишет | Разработчики | Разработчики / Тестировщики | Тестировщики (QA Automation) | | Количество в проекте| Тысячи | Сотни | Десятки |
Разработка через тестирование (TDD)
Традиционный подход к программированию выглядит так: разработчик пишет код, затем запускает его, проверяет глазами, и если все работает, пишет тесты (или не пишет их вообще, ссылаясь на нехватку времени).
Разработка через тестирование (Test-Driven Development, TDD) переворачивает этот процесс с ног на голову. В TDD вы сначала пишете тест для функции, которой еще не существует, и только потом пишете сам код.
Этот подход опирается на строгий цикл из трех шагов, который часто называют Red-Green-Refactor (Красный-Зеленый-Рефакторинг).
Шаг 1: Red (Красный)
Вы пишете тест, который описывает желаемое поведение новой функции. Поскольку самой функции еще нет, при запуске тест неизбежно падает (в консоли результат подсвечивается красным цветом).Например, мы хотим создать функцию, которая проверяет, является ли строка палиндромом (читается одинаково слева направо и справа налево). Мы пишем тест:
Запускаем — получаем ошибку NameError: name 'is_palindrome' is not defined. Это отлично, мы зафиксировали наши требования в виде кода.
Шаг 2: Green (Зеленый)
Теперь ваша задача — написать минимально возможный код, чтобы тест прошел (загорелся зеленым). На этом этапе не нужно думать о красоте кода или архитектуре. Главное — удовлетворить тест.Да, код выглядит глупо, но тест теперь проходит! Мы доказали, что система может перейти из нерабочего состояния в рабочее.
Шаг 3: Refactor (Рефакторинг)
Теперь, когда у вас есть работающий код, защищенный тестом, вы можете его улучшить (отрефакторить). Вы меняете внутреннюю реализацию функции, делая ее универсальной и элегантной. Если вы где-то ошибетесь, тест сразу загорится красным и предупредит вас.Запускаем тест — он все еще зеленый. Цикл завершен.
!Интерактивный симулятор TDD (Разработка через тестирование)
Зачем применять TDD?
Понимание жизненного цикла тестирования, умение выбирать правильный уровень пирамиды для проверки своего кода и применение практик вроде TDD — это то, что отличает начинающего программиста от уверенного инженера. Эти концепции станут фундаментом, на котором мы будем строить изучение конкретных инструментов Python в следующих материалах.