Это машинный перевод текста, который может содержать ошибки!
Теперь, когда мы создали классы и работали с валидацией, у нас есть хорошая основа для начала тестирования. Тестирование — важная часть процесса разработки, которая помогает нам убедиться, что наш код работает так, как ожидается.
Но как можно быть уверенным в том, что код функционирует должным образом, если его не тестируют?
Что такое модульное тестирование (Unit Testing)?
Модульное тестирование — это метод автоматического и систематического тестирования небольших частей нашего кода. В Python мы используем модуль с именем pytest для написания и запуска тестов. «Единица» (модуль) — это наименьшая тестируемая часть приложения, часто отдельная функция или метод. При использовании pytest важно соблюдать правильные соглашения о наименовании, чтобы pytest мог находить наши тесты, например, называть файлы тестов с префиксом test_, а функции тестов также с префиксом test_.
Пример модульного теста:
def test_add():
assert 0.3 + 0.3 + 0.3 == 0.9
Запускается вводом команды pytest в терминале.
Интересный факт
Код выше даст ошибку, потому что в Python выражение .3+.3+.3 равно 0.8999999999!
Задание 1 — Установка pytest
Установите pytest в вашей виртуальной среде. Для этого выполните следующую команду в терминале:
pip install pytest
Задание 2 — Создайте тест
Создайте новый файл в папке вашего проекта с именем test_data.py. В этом файле вам нужно создать тест для класса Person, который вы создали в предыдущем модуле. Тест должен проверять, что объект Person может быть создан со значениями, которые являются допустимыми.
Пример того, как может выглядеть тест:
from main import Person
def test_person_working():
bob_kaare = Person(name="Bob Kåre",
eye_color=EyeColor.BLUE,
phone_number=PhoneNumber("12345678"),
email=Email("bob_kaare@example.com"))
assert bob_kaare.name == "Bob Kåre"
assert bob_kaare.eye_color == EyeColor.BLUE
Этот тип тестирования называется «happy path» (сценарий успешного выполнения), поскольку мы проверяем, что всё работает должным образом при валидных значениях, и он не очень полезен.
Задача 3 — Тестирование валидации
Создайте несколько тестов в test_person.py, которые проверяют корректность работы валидации в Email и PhoneNumber. Протестируйте как допустимые, так и недопустимые значения. Здесь необходимо использовать функцию pytest под названием raises, которая проверяет выброс определенной ошибки.
import pytest
def test_exception():
with pytest.raises(KeyError):
my_dict = {"a": 1, "b": 2}
value = my_dict["c"] # Это вызовет исключение KeyError
Tip
Вы можете создавать столько функций, сколько хотите, при условии что имя функции начинается с test_.
Решение: Пример теста для недействительного электронного адреса
from main import Email
import pytest
def test_invalid_email():
with pytest.raises(ValueError):
email = Email("not-an-email")
Зачем это нужно?
Имея хорошие тесты для нашего кода, мы можем быть уверены в том, что он работает должным образом, и легко определить, если что-то пошло не так при внесении изменений в код. Это особенно важно в крупных проектах, где многие разработчики работают вместе, а ошибки допустить проще всего.
Видео: Почему тесты защищают код от новых ошибок
В видео объясняется, почему тестирование важно и как автоматизированные тесты могут выявлять ошибки после изменений в коде.
Например, используя такое программное обеспечение, как Jest или Selenium, можно автоматически тестировать веб-сайты, тем самым обеспечивая работоспособность всех компонентов после каждого изменения кода. Нам ведь хочется знать, что «регистрация пользователей», «оплата» и «вход» работают должным образом, верно?
Подумайте о следующих сценариях
Что происходит (или должно произойти), если..:
- Пользователь пытается зарегистрироваться по электронной почте, которая уже используется?
- У пользователя дата рождения в будущем?
- Пользователь вводит имя «jOHN dOE»?
Задание 4 - Автоматическое тестирование (CI)
Когда мы публикуем код на GitHub, мы можем настроить функцию GitHub Actions, которая автоматически запускает наши тесты каждый раз при внесении изменений в код. Это называется непрерывной интеграцией (CI), и она помогает нам убедиться в том, что наш код всегда работает должным образом.
Создайте файл с именем .github/workflows/pytest.yml в папке вашего проекта. В этот файл добавьте следующий код:
name: Pytest
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
# Установите любые другие зависимости, необходимые для вашего проекта
pip install -r requirements.txt
- name: Run tests with pytest
run: pytest
Если вы правильно его добавили, теперь у вас в репозитории GitHub появится новая вкладка с названием «Actions». Здесь вы сможете видеть, как ваши тесты автоматически запускаются каждый раз при внесении изменений в код, а также получать уведомления о том, если какой-либо из тестов завершится ошибкой (красный крестик и по электронной почте).
Примечание о структуре файлов
Ваша структура файлов определит будет ли работать GitHub Actions или нет. Убедитесь, что папка .github находится в корневой директории вашего проекта, а также существует папка tests, где находятся ваши файлы тестов.
При необходимости вы можете изменить файл pytest.yml, чтобы указать правильную директорию.
Файлы с действиями (Actions) также можно использовать для тестирования вашего кода на нескольких версиях Python или операционных системах; они также позволяют автоматически собирать и публиковать ваше программное обеспечение, например, размещать веб-сайт или обновлять приложение в App Store или Google Play.
Покрытие кода
Существует также такое понятие, как «Покрытие кода» (Code Coverage), которое может помочь вам увидеть, какая часть вашего кода фактически тестируется. Это полезно для того, чтобы определить, достаточно ли у вас тестов или есть ли части кода, которые вообще не подвергаются тестированию.
Некоторые работодатели требуют, чтобы определённый процент вашего кода был покрыт тестами перед его развёртыванием, чтобы обеспечить надёжность и корректность работы кода.

