Как новичку начать писать юнит-тесты на Python
Давно хотел написать серию статей, касаемо тестирования с позиции разработчика. В этой "открывающей" статье пробежимся по основным моментам написания юнитов, которые больше всего будут полезны джунам, которые уже хотят писать код "по-взрослому", а значит - покрывать тестами. А в конце посмотрим, что думает про юнит-тестирование AI. Будет интересно, поехали!
Шаг 1. Выбор фреймворка
Чтобы не писать свои велосипеды, мир Python предоставляет набор разнообразных фреймворков на выбор:
- стандартный модуль unittest, поставляемый уже сразу с дистрибутивом Python. Содержит определенное количество нужных примитивов, Mock-объектов, patch-заглушек и тд. Особенно радует наличие асинхронных моков - AsyncMock.
- Pytest, являющийся де-факто стандартом для тестирования (https://docs.pytest.org/) и имеющий кучу различных плагинов на разные случаи жизни.
- mockito - шикарный spying framework, который вместе с плагином pytest-mockito позволяет не просто проверять кейсы, но и отслеживать состояние, в котором assert не сработал. https://pypi.org/project/mockito/
Шаг 2. Создание отдельного тест-файла
* Ниже код будем рассматривать на примере pytest.
Файл должен начинаться с префикса "test_", например test_calc_functions.py. Имя файла должно подсказывать, что мы внутри него тестируем. Также необходимо убедиться, что чувствительный production-код, личные данные не попали в ваш тест-код.3. Написание тест-функции.
Шаг 3. Написание тест-функции
Тест-функция также должна начинаться с префикса "test_" и следовать тому, что она тестирует. Она должна включать assert блоки, которые проверяют соответствует ли результат выполнения тестируемой функции ожидаемому результату (expected result).
В большинстве кейсов мы используем оператор assert, который проверяет истинность выражения. Истинность выражения может выражаться в логической операции сравнения, результатом выполнения функции и тд.
Пример
При попытке явно вызвать assert на невалидном выражении - получим ошибку
Кейс, когда результат соответствует нашим ожиданиям называется позитивным
Напишем пользовательскую функцию и позитивный тест-кейс (помним про префикс test_).
Шаг 4. Запуск тестов
Используя фреймворк вы можете запускать свои тесты и проверять результаты на успех/ошибку. Конечно, можно запускать тесты и без фреймворка, на чистом python, используя assert. Но тогда многие возможности будут недоступны.
Если все тесты прошли успешно - фреймворк сообщит об этом зеленым выводом в консоль и сообщением. Если тесты упали - вывод будет красным. Необходимо поправить тест, либо исправить реализацию и повторить запуск снова.
Здесь я запускаюсь из-под виртуального окружения, вам же достаточно в консоли просто запустить
Сложные моменты для начинающих
При проведении занятий, заметил такую вещь - новичкам сложно сформулировать тест-кейс, ведь тут нужно написать проверку на проверку. Ниже приведу личные советы, как поправить эту ситуацию.
Первое - понять, что ты тестируешь? Для того, чтобы писать не формальные тесты, а качественные и вдумчивые - необходимо понимать ту доменную область, в которой этот код будет работать. Возвращаясь к ф-и сложения add - необходимо ответить на вопросы:
- как будет вызываться эта функция? сама или внутри другой?
- что эта функция вообще делает? что она НЕ делает?
- какие аргументы могут быть переданы? как должна вести себя при передачи аргументов другого типа? диапазон допустимых значений
- какие исключения может вызывать: стандартные или пользовательские?
Второе - понять, как ты будешь это тестировать? Будет ли это набор ручных тестов, или отдельное семейство юнит-тестов на фреймворке? Какие зависимости нужны? Как будут выглядеть тестовые данные, в каком формате?
Особенно стоит продумать негативные кейсы. Здесь попытаемся вызвать функцию add с невалидным аргументом-строкой. Очевидно, что если вызвать ее в боевом коде, получим ошибку невалидного типа.
Обернув код библиотечным контекстным менеджером, мы получим валидный негативный тест. В нем мы ожидаем возникновение исключения, поэтому он пройдет успешно.
В этом и суть негативных кейсов - успешный неуспех :)
Что же думает AI по этому поводу?
Вот что мне сгенерил Kandinsky
Но более всего понравился Шедеврум
Действительно, написание хороших читаемых тестов - это искусство ходьбы между болотами и лесами по пути домой.
Спасибо, что дочитали! Жду в следующий раз!
🖤 Подписывайтесь на мою телегу. Больше кода 🐍 - меньше багов 🪲!
Раньше я очень часто и много заказывала еду с доставкой. Особенно, когда болеешь, это очень удобно. Привезли готовенькое, подогрел, покушал. Отлично! И о том, как эту еду должны доставлять, я детально никогда не задумывалась. Пока сама не пришла в общепит. Об этом сегодня и поговорим.
Официально пока организация об этом не заявляла.