📖 Теория: Введение в автотестирование. Unit-тестирование

⚡ Кратко

Тестирование ПО — проверка соответствия реального и ожидаемого поведения программы. Автотестирование — выполнение этих проверок скриптами.

  • Пирамида: Unit (основание) → Integration → E2E (вершина)
  • Unit-тест проверяет одну функцию/метод в изоляции
  • pytest: def test_xxx(fixture): assert ...
  • Фикстура: @pytest.fixture — общая подготовка ресурса для тестов
  • Маркировки: skip, skipif, xfail, пользовательские

1. Что такое тестирование программного обеспечения

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

Полезно знать: тестирование — это не просто поиск багов. Если дефекты не найдены, это не значит, что тестирование было бесполезным: оно также подтверждает, что система работает корректно в рамках протестированных сценариев.

Ключевые аспекты тестирования

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

Представьте, что вы тестируете карандаш. Задача — не просто искать дефекты (сломанный грифель, трещины), но и проверить, выполняет ли карандаш свои функции: пишет ли он, насколько легко стирается ластиком, как долго хватает ресурса. Если карандаш пишет, но очень бледно — это тоже отклонение от ожиданий.

2. Автоматизация тестирования

Автоматизация тестирования — это процесс использования инструментов и скриптов для выполнения тестов с минимальным участием человека.

Выгода от автоматизации тестирования

  1. Скорость выполнения тестов. Автоматизированные тесты работают быстрее. Проверка на сотнях конфигураций браузеров с помощью Selenium занимает считанные минуты — вручную это заняло бы дни.
  2. Повторяемость и масштабируемость. Тесты легко повторять — идеально для регрессионного тестирования. Перед каждым релизом запускается один набор тестов.
  3. Снижение затрат на долгосрочные проекты. Начальные инвестиции окупаются с каждым запуском: тесты выполняются без участия человека.
  4. Точность и исключение человеческого фактора. Скрипты выполняют однообразные задачи с неизменной точностью.
  5. Поддержка сложных сценариев. Автоматизация позволяет проверять нагрузочное тестирование, API с миллионами запросов — то, что трудно проверить вручную.

3. Пирамида тестирования

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

Три уровня пирамиды (снизу вверх):
  1. Модульные тесты (Unit Tests)
  2. Интеграционные тесты (Integration Tests)
  3. End-to-End тесты (E2E Tests)

Уровень 1: Модульные тесты (Unit Tests)

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

Уровень 2: Интеграционные тесты (Integration Tests)

  • Средний слой пирамиды.
  • Проверяют взаимодействие между различными модулями или компонентами.
  • Сложнее в реализации и медленнее, чем unit-тесты.
  • Пример: тест связи между фронтендом и API.

Уровень 3: End-to-End тесты (E2E Tests)

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

Принципы пирамиды

  • Больше unit-тестов, меньше интеграционных, ещё меньше E2E.
  • Фокус на автоматизации нижних уровней для ускорения разработки.
  • Оптимизация затрат за счёт снижения числа дорогих тестов верхнего уровня.
Аналогия:

Представьте строительство дома. Модульные тесты — это проверка качества каждого кирпича. Интеграционные — проверка прочности стен. E2E — финальная проверка всего дома: двери, окна, инженерные системы.

4. pytest — инструмент для тестирования в Python

pytest — популярная библиотека для тестирования Python-кода. Проста в использовании, поддерживает автоматический запуск тестов и генерацию отчётов.

Установка

pip install pytest

Соглашения об именовании

pytest автоматически находит тесты, если:

  • Имена файлов начинаются с test_ или заканчиваются на _test.
  • Имена функций начинаются с test_.

Преимущества pytest перед ручными assert

  1. Простота и лаконичность: тесты легко писать и читать.
  2. Гибкость фикстур: общие настройки и ресурсы для тестов.
  3. Обработка исключений: pytest.raises() — проверить, что метод выбрасывает ожидаемую ошибку.
  4. Отчёты: подробная информация о причинах провала тестов.

5. Фикстуры pytest

Фикстуры позволяют задавать общие настройки и ресурсы, которые используются несколькими тестами. Это устраняет дублирование кода создания объектов.

# test_calculator.py
import pytest
from calculator import Calculator

@pytest.fixture
def calculator():
    return Calculator()

def test_sum_positive_numbers(calculator):
    assert calculator.sum(4, 5) == 9

def test_sum_negative_numbers(calculator):
    assert calculator.sum(-6, -10) == -16
Как это работает: pytest видит параметр calculator в сигнатуре теста, находит одноимённую фикстуру и передаёт результат её вызова в тест. Каждый тест получает свой экземпляр.

6. Маркировки тестов в pytest

Маркировки — способ пометить тесты специальными декораторами, чтобы управлять их выполнением.

Пропуск тестов (@pytest.mark.skip)

@pytest.mark.skip(reason="Тест будет исправлен позже")
def test_sum_positive_nums():
    calculator = Calculator()
    assert calculator.sum(4, 5) == 9

Условный пропуск (@pytest.mark.skipif)

import sys

@pytest.mark.skipif(sys.version_info < (3, 8), reason="Требуется Python 3.8 или выше")
def test_sum_positive_nums():
    calculator = Calculator()
    assert calculator.sum(4, 5) == 9

Ожидаемый сбой (@pytest.mark.xfail)

@pytest.mark.xfail(strict=True, reason="Метод в процессе разработки")
def test_sum_positive_nums():
    calculator = Calculator()
    assert calculator.sum(4, 5) == 10  # Умышленная ошибка

Если тест провалится — он помечается xfail. Если неожиданно пройдёт — xpass.

Пользовательские маркеры

@pytest.mark.positive_test
def test_sum_positive_nums():
    calculator = Calculator()
    assert calculator.sum(4, 5) == 9

@pytest.mark.positive_test
def test_div_positive():
    calculator = Calculator()
    assert calculator.div(10, 2) == 5

Запуск по маркеру: pytest -m positive_test

Чтобы избежать предупреждений pytest о неизвестных маркерах, документируйте их в pytest.ini:

# pytest.ini
[pytest]
markers =
    positive_test: Тесты для позитивных сценариев

Выборочный запуск тестов

# Запускать только тесты, в имени которых есть "sum"
pytest -k "sum"

# С помощью pytest.ini для постоянной фильтрации:
# [pytest]
# python_functions = *sum*

← К оглавлению урока