Python: Автоматическое тестирование
Теория: Модульные тесты
Изученной информации уже достаточно для тестирования в повседневной практике разработки. Перед тем, как погружаться в более сложные темы и возможности Pytest, пройдем полный путь тестирования библиотеки. Мы поговорим об организации тестов, хороших и плохих практиках. Это поможет сформировать правильное отношение к тестированию в целом.
Что такое модульное тестирование
В этом уроке мы разберем основы модульного тестирования. Это тестирование направлено на проверку модулей программы в изоляции от всех остальных частей. Эти тесты обычно тестируют базовые конструкции языка: функции, модули, классы. Такие тесты не дают никаких гарантий работы всего приложения в целом, но хорошо помогают тогда, когда какой-то модуль программы имеет сложную логику.
Попробуем протестировать стек. Напомним, что стек представляет собой список элементов, организованных по принципу LIFO (Last In First Out). По такому принципу данные кладутся в стек в одном порядке, а извлекаются в обратном.
Как правило, сам стек используется для реализации алгоритмов. Он часто используется в низкоуровневом коде, например, внутри языков программирования или в операционных системах:
Тестируем основную функциональность
Теперь напишем первый тест. Первый тест всегда должен проверять позитивный сценарий — тот, в котором задействована основная функциональность тестируемого компонента:
Этот тест проверяет, правильно ли работают два основных метода без учета пограничных случаев. Для этого внутри теста выполняются два утверждения, которые по очереди проверяют извлекаемые значения из стека.
В интернете можно встретить мнение, что несколько проверок в рамках одного теста — это неправильно. Считается, что тесты нужно детализировать максимально подробно и создавать новый тест на каждую проверку:
Выделять в отдельный тест точно стоит другие сценарии, которые требуют других данных или выполняют другую последовательность действий. Но такой подход работает не всегда. Нередко он приводит к серьезному раздуванию кода и дублированию. При этом выгода неочевидна.
Тестируем дополнительную функциональность
Следующим тестом будет тест на дополнительные функции стека. К таким у нас относится проверка на пустоту:
В этом тесте проверяются сразу три ситуации:
- Начальное состояние стека
- Состояние стека после добавления элементов
- Состояние стека после извлечения всех элементов
В принципе, этого достаточно. Хотя в теории возможны ситуации, при которых проверка на not все равно сломается. Нужно ли пытаться найти все варианты? Не нужно. Каждая написанная строчка кода в проекте — потенциальное место для изменения в случае правок. Если есть сомнения, нужно ли писать проверку или нет, то лучше не пишите. Так вы найдете тот минимум, который стоит писать. Редкие ситуации требуют покрытия тестами только тогда, когда они критичны для работоспособности.
Пограничные случаи
Ну, и последнее, что можно протестировать — поведение функции pop(), когда в стеке нет ни одного элемента. По задумке стек выбрасывает исключение, если из него попытались взять элемент, когда тот был пустой. То есть эта ситуация рассматривается как ошибочная, программист всегда должен убеждаться в том, что стек не пустой:
Не всегда пограничные случаи так легко увидеть. Маловероятно, что любой программист сможет сразу написать все нужные тесты.
Представим, что в коде возникла ошибка, для которой не было теста. В таком случае сначала напишите тест, который воспроизводит эту ошибку, и затем уже чините ее. Только так можно поддерживать достаточный уровень надежности, не превращая разработку в непрерывную починку багов.

