Разработка качественного сервиса бронирования авиабилетов требует продуманного тестирования на разных уровнях. Рассмотрим основные виды тестов и стратегии их организации, а также как они соотносятся с архитектурными паттернами (DDD – предметно-ориентированное проектирование).

Обзор видов тестов

Модульные тесты (unit tests).

Это быстрые, изолированные проверки отдельных классов или функций. Они не должны зависеть от сети, базы данных или других сервисов. Модульные тесты дают мгновенную обратную связь, помогают обнаружить дефекты на раннем этапе и гарантируют корректность бизнес-логики в кодеhabr.comtaimila.com. Они часто покрывают основные сценарии методов доменных объектов. Например, тестирование метода reserve_seat() у объекта Flight в сервисе бронирования может выглядеть так:

class Flight:
    def __init__(self, flight_number, seats_total):
        self.flight_number = flight_number
        self.seats_total = seats_total
        self.seats_reserved = 0

    def reserve_seat(self):
        if self.seats_reserved < self.seats_total:
            self.seats_reserved += 1
            return True
        return False

# Пример модульного теста для доменной логики
def test_reserve_seat():
    flight = Flight("AB123", seats_total=2)
    assert flight.reserve_seat() == True
    assert flight.reserve_seat() == True
    assert flight.reserve_seat() == False  # мест больше нет

Интеграционные тесты.

Они проверяют взаимодействие между модулями, компонентами и сервисами приложенияhabr.comdev.to. Интеграционные тесты могут работать с реальной или тестовой базой данных, симулировать вызовы API, проверять корректность обмена данными между подсистемами. Например, интеграционный тест для сервиса бронирования может создавать рейс в тестовой БД и проверять, что при бронировании запись корректно сохраняется и доступна другим компонентам. Такие тесты обычно медленнее модульных, но выявляют ошибки на стыке компонентов, невидимые при чистом юнит-тестировании.

Сквозные (end-to-end) тесты.

Это самые тяжёлые тесты, эмулирующие полное пользовательское поведение (например, через веб-интерфейс или HTTP API). Они проверяют основные пользовательские сценарии: поиск рейса, выбор места, оформление билета и т.д. Сквозные тесты медленные и дорогие в поддержке, поэтому их количество должно быть минимальнымhabr.comhabr.com. Обычно они покрывают критически важные пути (авторизация, оплата) и запускаются реже. Например, сквозной тест может запускать веб-клиент, имитировать действия пользователя на сайте и проверять, что билет успешно создаётся.

Каждый вид тестов дополняет другие: модульные тесты обеспечивают надёжность низкого уровня, интеграционные – проверяют взаимодействия, а сквозные – валидируют целые бизнес-сценарии на наиболее высоком уровне. В совокупности такая стратегия позволяет быстро находить ошибки и обеспечивать стабильность системы.

Стратегии тестирования

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

Основой классической пирамиды являются модульные тесты (~70% тестового покрытия)habr.com. Средний уровень занимают интеграционные тесты (~20–25%), проверяющие обмен данными между модулями и внешними сервисамиhabr.com. Вершину пирамиды составляют сквозные E2E-тесты (~5–10%), эмулирующие работу пользователя и покрывающие только самые важные сценарииhabr.com.

Ключевые преимущества пирамиды:

Недостатки пирамиды могут проявляться в распределённых системах: в микросервисах часто требуется больше интеграционных и контрактных тестов, поэтому классическая пирамида может не учесть сложность общения между сервисами. Тем не менее, в большинстве случаев пирамидальный подход считается оптимальным, так как экономит усилия и ускоряет выпуск фичhabr.comhabr.com.

Ромб тестирования