Как писать и запускать модульные тесты на Python с помощью PyTest
Когда вы пишете код на Python, важно убедиться, что ваш код работает должным образом. Один из лучших способов сделать это — использовать модульные тесты, которые помогут вам проверить, правильно ли работают небольшие части (или блоки) вашего кода.
В этой статье мы узнаем, как писать и проводить эффективные модульные тесты на Python с помощью PyTest, одного из самых популярных фреймворков для тестирования Python.
Что такое модульные тесты?
Модульные тесты — это небольшие, простые тесты, которые сосредоточены на проверке одной функции или небольшого фрагмента кода. Они помогают гарантировать, что ваш код работает должным образом и может выявлять ошибки на ранней стадии.
Модульные тесты могут быть написаны для различных частей вашего кода, таких как функции, методы и даже классы. С помощью модульных тестов можно протестировать код, не запуская всю программу.
Зачем использовать PyTest?
PyTest — это популярная среда тестирования для Python, которая упрощает написание и проведение тестов.
Он прост в использовании и имеет множество полезных функций, таких как:
- Он позволяет писать простые и понятные тест-кейсы.
- Он предоставляет расширенные функции, такие как фикстуры, параметризованные тесты и плагины.
- Он хорошо работает с другими инструментами тестирования и библиотеками.
- Он генерирует легко читаемые результаты тестов и отчеты.
Настройка PyTest в Linux
Прежде чем мы начнем писать тесты, нам нужно установить PyTest. Если у вас не установлен PyTest, вы можете установить его с помощью менеджера пакетов Python под названием pip.
pip install pytest
Как только PyTest будет установлен, вы будете готовы приступить к написанию тестов!
Написание вашего первого теста с помощью PyTest
Давайте начнем с написания простой функции, а затем напишем тест для нее.
Шаг 1: Напишите простую функцию
Во-первых, давайте создадим функцию Python, которую мы хотим протестировать. Допустим, у нас есть функция, которая складывает два числа:
# add.py
def add(a, b):
return a + b
Это простая функция, которая принимает два числа a и b, складывает их вместе и возвращает результат.
Шаг 2: Напишите тест для функции
Теперь давайте напишем тест для функции add. В PyTest тесты записываются в отдельных файлах, обычно называемых test_*.py
чтобы упростить идентификацию тестовых файлов.
Создайте новый файл с именем test_add.py
и напишите следующий тестовый код:
# test_add.py
from add import add
def test_add_numbers():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
Пояснение к приведенному выше коду:
- Импортируем функцию
add
из файлаadd.py
. - Мы определяем тестовую функцию с именем
test_add_numbers()
. В PyTest тестовая функция должна начинаться со словаtest_
. - Внутри тестовой функции мы используем оператор
assert
, чтобы проверить, соответствует ли результат вызова функцииadd
ожидаемому значению. Если условие в оператореassert
равноTrue
, тест проходит, в противном случае он завершается ошибкой.
Шаг 3: Запустите тест
Чтобы запустить тест, откройте терминал и перейдите в каталог, где находится файл test_add.py
, а затем выполните следующую команду:
pytest
PyTest автоматически найдет все тестовые файлы (те, которые начинаются с test_
) и запустит тесты внутри них. Если все работает правильно, вы должны увидеть такой вывод:
Точка (.)
указывает на то, что тест пройден. Если возникали какие-либо проблемы, PyTest выдавал сообщение об ошибке.
Написание более сложных тестов
Теперь, когда мы знаем, как написать и запустить базовый тест, давайте рассмотрим некоторые более продвинутые функции PyTest.
Тестирование на наличие ожидаемых исключений
Иногда требуется проверить, создает ли ваш код правильные исключения, когда что-то идет не так. Вы можете сделать это с помощью функции pytest.raises().
Допустим, мы хотим протестировать функцию, которая делит два числа. Мы хотим вызвать исключение, если второе число равно нулю (чтобы избежать деления на ноль ошибок).
Вот функция деления
:
# divide.py
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
Теперь давайте напишем тест для этой функции, который проверяет, возникает ли ошибка ValueError
, когда мы пытаемся разделить на ноль:
# test_divide.py
from divide import divide
import pytest
def test_divide_numbers():
assert divide(10, 2) == 5
assert divide(-10, 2) == -5
assert divide(10, -2) == -5
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(10, 0)
Объяснение кода:
- Мы добавили новую тестовую функцию
под названием test_divide_by_zero()
. - Внутри этой функции мы используем
pytest.raises(ValueError)
для проверки, возникаетли ValueError
при вызове функции деления с нулем в качестве второго аргумента.
Запустите тесты еще раз с помощью команды pytest. Если все работает правильно, вы должны увидеть этот вывод:
Использование фикстур для настройки и очистки
В некоторых случаях может потребоваться настроить определенные условия перед запуском тестов или выполнить очистку после их завершения. PyTest предоставляет приспособления для решения этой проблемы.
Приспособление — это функция, которую можно использовать для настройки или демонтажа условий для испытаний. Фикстуры часто используются для создания объектов или подключения к базам данных, которые необходимы для тестов.
Ниже приведен пример использования фикстуры для настройки временного каталога для тестирования файловых операций:
# test_file_operations.py
import pytest
import os
@pytest.fixture
def temporary_directory():
temp_dir = "temp_dir"
os.mkdir(temp_dir)
yield temp_dir # This is where the test will run
os.rmdir(temp_dir) # Cleanup after the test
def test_create_file(temporary_directory):
file_path = os.path.join(temporary_directory, "test_file.txt")
with open(file_path, "w") as f:
f.write("Hello, world!")
assert os.path.exists(file_path)
Объяснение кода:
- Мы определяем фикстуру с именем
temporary_directory
, которая создает временный каталог перед тестом и удаляет его впоследствии. - Тестовая функция
test_create_file()
использует эту фикстуру для создания файла во временном каталоге и проверяет, существует ли файл.
Запустите тесты еще раз с помощью команды pytest. PyTest автоматически обнаружит и использовать приспособление.
Параметризуйте свои тесты с помощью pytest
Иногда требуется выполнить один и тот же тест с разными входными данными. PyTest позволяет легко сделать это с помощью параметризации.
Допустим, мы хотим протестировать нашу функцию add
с несколькими парами чисел. Вместо того, чтобы писать отдельные тестовые функции для каждой пары, мы можем использовать pytest.mark.parametrize
для запуска одного и того же теста с разными входными данными.
# test_add.py
import pytest
from add import add
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5),
(-1, 1, 0),
(0, 0, 0),
(100, 200, 300)
])
def test_add_numbers(a, b, expected):
assert add(a, b) == expected
Объяснение кода:
- Мы используем декоратор
pytest.mark.parametrize
для определения нескольких наборов входных данных (a
,b
иexpected
). Тестовая функция test_add_numbers()
будет выполняться один раз для каждого набора входных параметров.
Запустите тесты снова с помощью команды pytest, которая запустит тест четыре раза, по одному разу для каждого набора входных данных.
Заключение
В этой статье мы узнали, как писать и запускать эффективные модульные тесты на Python с помощью PyTest, чтобы выявлять ошибки на ранней стадии и гарантировать, что ваш код работает так, как ожидалось.
PyTest упрощает написание и выполнение этих тестов, а благодаря своим мощным функциям вы можете справляться с более сложными задачами тестирования по мере вашего роста в путешествии по Python.