Современный Python: пишем модульные тесты и применяем соглашения о коммитах в Git

Рассказываем, как начинающему разработчику проводить модульное тестирование вашего Python-приложения, и с помощью чего обеспечить и проверить сообщения о фиксации в Git.
Эта вторая статья из цикла, в котором рассказывается о лучших практиках современного Python. В этом цикле статей все примеры основаны на реализации простого проекта, который представляет собой функцию Python, которая суммирует данные, присутствующие в pandas DataFrame. Функция выводит количество строк и столбцов и частоту каждого типа данных, присутствующих в pandas DataFrame.
Хорошая практика разработки программного обеспечения всегда приносит много долгосрочных выгод. Например, написание модульных тестов позволяет поддерживать большие кодовые базы и гарантирует, что определенный фрагмент вашего кода ведет себя так, как ожидается. Написание последовательных коммитов в Git также улучшает сотрудничество между участниками проекта. Хорошо составленные сообщения коммитов Git открывают путь к автоматическому версионированию и автоматически генерируемым файлам журнала изменений. Поэтому сейчас в сообществе разработчиков предпринимается множество попыток нормализовать сообщения, написанные в наших Git-коммитах.
В первой части этой серии мы настраивали наш проект, устанавливая различные версии Python с помощью pyenv
, устанавливая локальную версию Python с помощью pyenv
, инкапсулируя его в виртуальную среду с помощью poetry
. Здесь мы покажем более подробно, как проводить модульное тестирование вашего Python-приложения и как обеспечить и проверить сообщения о коммитах в Git. Исходный код, связанный с этой статьей, опубликован на GitHub.
Содержание
- Тестирование кода
- Применение правил по созданию сообщений Git-коммитов в проекте Python
- Заключение
- Краткая памятка
Тестирование кода
Перейдите в корневой каталог вашего проекта и активируйте виртуальное окружение:
Примечание переводчика: Поскольку со времени написания оригинальной статьи требования numpy
к версии Python изменились, перед добавлением зависимостей необходимо внести изменения в файл pyproject.toml
:
Добавим несколько зависимостей с помощью poetry
:
Флаг -D указывает, что зависимость применяется только к среде разработки.
Исходя из ожидаемого результата работы проекта, наша программа состоит из трех шагов:
- Получение формы pandas DataFrame
- Получение частоты типов pandas
dtypes
. - Объединение этих двух результатов в единый DataFrame, который будет использован для вывода окончательного результата.
После получения окончательного DataFrame выводится результат, как показано выше. В связи с этим наш код может выглядеть следующим образом:
Теперь начнем писать модульные тесты. Мы будем использовать инструмент unittest
, доступный в стандартной библиотеке Python. Возможно вы помните, что в предыдущей статье pytest был определен как зависимость для тестирования. Это не проблема, потому что pytest
нативно запускает тесты, написанные с помощью библиотеки unittest
.
Читайте другие статьи в блоге:
20 советов для будущих программистов, которые ищут свою первую работу в IT: как получать удовольствие от собеседований
Юнит-тесты — это методы, которые, как ожидает unittest
, будут описаны внутри классов Python. Выберите для своих тестовых классов и методов описывающее имя — оно должно начинаться с test_
. Дополнительно unittest
использует ряд специальных тестовых методов, унаследованных от класса unittest.TestCase
.
На практике тест должен:
- Охватывать одну функцию
- Быть автономным
- Не требовать внешних инструкций
- Воссоздавать условия достижения результата.
Чтобы воссоздать необходимую рабочую среду, необходимо написать код настройки. Если этот код окажется избыточным, реализуйте метод setUp()
, который будет выполняться перед каждым тестом. Это очень удобно для повторного использования и реорганизации кода. В зависимости от сценария использования, возможно придется выполнять регулярные операции после выполнения тестов. Для этого вы можете использовать метод tearDown()
.
Сначала вы можете посмотреть unit-тест, который мы реализовали для функции data_summary()
:
Метод setUp()
инициализирует два разных pandas DataFrame. self.exp_df
— это результирующий DataFrame, который мы ожидаем получить после вызова функции data_summary()
, а self.df
— это DataFrame, который используется для тестирования наших функций. Сейчас ожидается, что тесты окажутся неудачными, потому что логика не была реализована. Для тестирования с помощью poetry
используйте команду:
Использование флага -v
позволяет получить более подробный вывод результатов тестирования. Вы можете видеть, что тесты помечены в соответствии с именами классов и функций, которые вы задали. В нашем случае это ::TestDataSummary::test_data_summary
.
Поменяем код для соответствия unit-тестам:
Снова запустим тесты:
И последнее. В наших тестах мы не проверяли фактический вывод. Наш модуль предназначен для вывода строкового представления сводки DataFrame. Существуют решения для достижения этой цели с помощью unittest
, но мы будем использовать pytest
для этого теста. Удивительно, не правда ли? Как уже говорилось, pytest
очень хорошо работает с unittest
, и сейчас мы это проиллюстрируем. Вот код для этого теста:
Обратите внимание на декоратор @pytest.fixture(autouse=True)
и функцию, которую он оборачивает (_pass_fixture)
. В терминологии модульного тестирования этот метод называется фикстурой (fixture). Фикстуры - это функции (или методы, если Вы используете подход ООП), которые будут выполняться перед каждым тестом, к которому они применяются. Фикстуры используются для передачи данных в тесты. Они выполняют ту же задачу, что и метод setUp()
, который мы использовали ранее. Здесь мы используем заранее определенное фикстуру под названием capsys
для захвата стандартного вывода (stdout
) и повторного использования его в нашем тесте. Теперь изменим соответствующим образом функцию display_summary()
:
Ещё раз запустим тесты:
Тесты прошли успешно. Пришло время зафиксировать нашу работу и поделиться ею, например, опубликовав на GitHub. Перед этим давайте подробно рассмотрим, как правильно сообщать о нашей работе с помощью сообщений о коммитах Git, соблюдая и поддерживая единый стандарт.
Читайте другие статьи в блоге:
Как принять участие в работе Open Source проектов на GitHub. Краткое руководство для начинающих
Применение правил по созданию сообщений Git-коммитов в проекте Python
Написание оптимальных Git-коммит сообщений - непростая задача. Сообщения должны быть четкими, читаемыми и понятными в долгосрочной перспективе. Спецификация Conventional Commits предлагает набор правил для создания однозначной истории коммитов. На Хекслете есть большая статья, посвященная правильному именованию коммитов.
Использование commitizen
Мы будем использовать пакет commitizen для интеграции Conventional Commits в наш проект на Python. Добавим этот пакет в зависимости разработчика:
Чтобы настроить commitizen
для своего проекта, выполните команду cz init
. Она предложит нам ответить на ряд вопросов:
Выберем здесь все варианты по умолчанию, так как они полностью соответствуют нашей реальной ситуации. Последний вопрос спрашивает нас, нужно ли использовать хук pre-commit. Мы собираемся вернуться к этому позже. Поэтому пока просто ответим «нет»(n). Если мы посмотрим на файл pyproject.toml
, то увидим, что была добавлена новая запись под названием [tool.commitizen]
:
Проверить коммит-сообщение, можно при помощи следующей команды:
Наше сообщение отклонено, потому что оно не соответствует выбранным правилам для коммит-сообщений. Последняя строка предлагает некоторые шаблоны для использования. Уделите немного времени чтению документации о соглашении о коммитах и выполните команду cz info
, чтобы распечатать краткую документацию:
Эта команда подскажет вам, как написать сообщение о коммите. Здесь формат должен быть таким: «[тип]: [СООБЩЕНИЕ]». Для нас это выглядит так:
Очень хорошо, наше коммит-сообщение считается корректным. Но подождите. Проверять коммит-сообщения каждый раз с помощью commitizen
может быть утомительно, и это не даёт гарантии, что коммит будет принят. Было бы лучше автоматически проверять сообщение каждый раз, когда мы используем команду git commit
. Именно в этом случае в действие вступает pre-commit
хук.
Автоматическое соблюдение соглашений о Git-коммитах при помощи pre-commit
Хуки Git полезны для автоматизации и выполнения некоторых действий на разных этапах жизненного цикла Git. Хук pre-commit
позволяет запускать скрипты до того, как будет выполнен Git-коммит. Мы можем использовать хук для проверки сообщений о коммитах и предотвращения использования Git сообщения, которое не соответствует нашим ожиданиям. Хук активен как из командной строки, так и из любых инструментов, взаимодействующих с репозиторием Git, в котором зарегистрирован хук, включая вашу любимую IDE.
pre-commit — это фреймворк для управления и поддержки многоязычных хуков pre-commit
. Если вы хотите узнать больше о внутреннем устройстве и спектре возможностей pre-commit
, то можете прочитать документацию по его использованию.
Чтобы установить pre-commit
, просто выполните команду:
Для автоматизации проверки коммита Git нам сначала нужно создать конфигурационный файл .pre-commit-config.yaml
:
Далее мы можем установить хук с источником, определенным в параметре repo
:
Теперь, когда все готово, мы можем исполь��овать наш Git-хук:
pre-commit
устанавливает среду для выполнения своих проверок. Как вы можете видеть здесь, сообщение о коммите прошло проверку. В завершение мы можем закоммитить изменения, внесенные в файлы сборки (poetry.lock
, pyproject.toml
) и наш модуль:
Теперь мы можем отправить все в наш репозиторий GitHub:
Заключение
Мы рассмотрели несколько тем:
-
На первом этапе мы узнали, как писать модульные тесты для вашего кода. Писать тесты до кода поможет вам уточнить API и ожидаемый результат до реализации в коде. Мы использовали
unittest
, который уже доступен в стандартной библиотеке Python. Также было продемонстрировано использование библиотекиpytest
для написания тестов. Очень удобно то, что pytest с самого начала поддерживает классunittest.TestCase
. Вы можете писать свои тесты с помощью любой из двух библиотек или даже смешивать их в зависимости от ваших потребностей и иметь одну общую команду для запуска всех тестов. -
Мы рассмотрели, как обеспечить соблюдение хороших практик при написании сообщений о коммитах в Git. Предлагаемое нами решение основано на использовании двух пакетов Python: commitizen и pre-commit. Первый предоставляет инструменты для проверки соответствия сообщения выбранным вами соглашениям. Второй автоматизирует процесс с помощью Git-хука.
Краткая памятка
poetry
-
Добавьте зависимости проекта:
`poetry add [package_name]`
-
Добавьте зависимости для разработки:
`poetry add -D [package_name]`
-
Запуск тестов:
` poetry run pytest`
commitizen
-
Инициализация commitizen:
`cz init`
-
Проверка коммита:
` cz check -m "YOUR MESSAGE"`
pre-commit
-
Создание файла конфигурации по умолчанию:
`pre-commit sample-config`
-
Установить git-хук:
`pre-commit install --hook-type [hook_name]`
Никогда не останавливайтесь:
В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами — на Хекслете есть сотни курсов по разработке на разных языках и технологиях
Александр Бурченко
4 года назад