Проверка функций в Python с помощью модульных тестов
Основные варианты тестирования функций
Как эффективно тестировать функции с помощью pytest?
Наиболее распространённый и удобный способ - использование фреймворка pytest. Он позволяет писать простые тесты с обычными assert, поддерживает параметризацию, фикстуры и автоматическое обнаружение тестовых файлов.
# Файл test_math_func.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0A b test python (a/b тестирование в python)
Для запуска тестов достаточно выполнить в терминале: pytest test_math_func.py. Система сама найдёт все функции, начинающиеся на test_.
test_ или функция не содержит префикса test. Решение - следовать соглашениям pytest: имена файлов test_*.py, функции test_*.
Для проверки исключений используется pytest.raises:
import pytest
def divide(a, b):
if b == 0:
raise ZeroDivisionError("деление на ноль")
return a / b
def test_divide_zero():
with pytest.raises(ZeroDivisionError, match="деление на ноль"):
divide(10, 0)Python code tests (тестирование кода в python)
Параметризация позволяет запускать один тест с разными данными без дублирования кода:
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(0, 0, 0),
(-5, 5, 0),
])
def test_add_parametrized(a, b, expected):
assert add(a, b) == expected
Py test python (написание тестов на python (pytest))
Incorrect number of arguments.
Как встроить тесты прямо в документацию функции?
Модуль doctest извлекает примеры из docstring и проверяет их выполнение. Это удобно для простых функций с очевидным поведением.
def multiply(a, b):
"""
Возвращает произведение двух чисел.
>>> multiply(3, 4)
12
>>> multiply(0, 100)
0
>>> multiply(-2, 5)
-10
"""
return a * b
if __name__ == "__main__":
import doctest
doctest.testmod()тесты алгоритмы и программирование python (тестирование алгоритмов и программ на python)
Запуск: python mymodule.py - если тесты пройдены, вывода не будет. При ошибке показывается различие.
Как использовать классический unittest из стандартной библиотеки?
Модуль unittest предоставляет объектно-ориентированный подход с классами наследуемыми от TestCase.
import unittest
def square(n):
return n * n
class TestSquareFunction(unittest.TestCase):
def test_positive(self):
self.assertEqual(square(5), 25)
def test_negative(self):
self.assertEqual(square(-3), 9)
def test_zero(self):
self.assertEqual(square(0), 0)
if __name__ == '__main__':
unittest.main()тестирование функций python (тестирование функций в python)
Запуск: python test_file.py. Методы assertEqual, assertTrue, assertRaises - основные инструменты.
unittest.TestCase - тогда тесты не будут распознаны как тестовые методы. Решение - всегда указывать class MyTest(unittest.TestCase).
Как изолировать функцию от внешних зависимостей с помощью unittest.mock?
При тестировании функций, которые обращаются к внешним API или базам данных, применяют моки. Библиотека unittest.mock (или pytest-mock с pytest) позволяет подменить объекты.
from unittest.mock import patch
import requests
def get_user_name(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()["name"]
def test_get_user_name():
with patch('requests.get') as mock_get:
mock_get.return_value.json.return_value = {"name": "Alice"}
result = get_user_name(1)
assert result == "Alice"
mock_get.assert_called_once_with("https://api.example.com/users/1")
В pytest можно использовать плагин pytest-mock и фикстуру mocker.
ModuleNotFoundError или AssertionError при проверке вызова.
Расширенные примеры тестирования функций
Тестирование асинхронных функций
Для асинхронных функций (async/await) требуется pytest-asyncio. Установка: pip install pytest-asyncio.
import pytest
async def fetch_data(url):
# имитация запроса
return {"status": 200, "data": "OK"}
@pytest.mark.asyncio
async def test_fetch_data():
result = await fetch_data("http://example.com")
assert result["status"] == 200
Использование временных файлов (tmpdir)
Фикстура tmpdir в pytest создаёт временную директорию для каждого теста, которая удаляется после завершения.
import pytest
def write_to_file(path, content):
with open(path, 'w') as f:
f.write(content)
def test_write_to_file(tmpdir):
file_path = tmpdir.join("output.txt")
write_to_file(str(file_path), "Hello, pytest!")
with open(str(file_path)) as f:
assert f.read() == "Hello, pytest!"
Тест проходит успешно, файл создаётся и удаляется.
Тестирование функций с побочными эффектами
Функция может изменять глобальное состояние или записывать в лог. Для проверки логов используют caplog из pytest.
import logging
import pytest
def log_message(logger, msg):
logger.info(msg)
def test_log_message(caplog):
logger = logging.getLogger("test_logger")
with caplog.at_level(logging.INFO):
log_message(logger, "Тестовое сообщение")
assert "Тестовое сообщение" in caplog.text
Параметризация с несколькими аргументами и сложными типами
В pytest можно передавать списки, словари и другие объекты как параметры.
import pytest
def merge_dictionaries(a, b):
merged = a.copy()
merged.update(b)
return merged
@pytest.mark.parametrize("a,b,expected", [
({"x": 1}, {"y": 2}, {"x": 1, "y": 2}),
({"a": 10}, {"a": 20}, {"a": 20}),
])
def test_merge(a, b, expected):
assert merge_dictionaries(a, b) == expected
Оба теста проходят.
Тестирование встроенных функций с помощью pytest и hypothesis
Библиотека hypothesis генерирует случайные тестовые данные для поиска граничных случаев.
from hypothesis import given, strategies as st
def factorial(n):
if n < 0:
raise ValueError("Факториал отрицательного числа не определён")
if n == 0:
return 1
return n * factorial(n - 1)
@given(st.integers(min_value=0, max_value=20))
def test_factorial_positive(n):
result = factorial(n)
assert result >= 1
if n > 0:
assert result % n == 0
Hypothesis генерирует множество значений, тесты могут выявить ошибки для необычных входных данных.
Проверка покрытия кода (coverage)
Утилита coverage.py показывает, какие строки кода выполняются во время тестирования. Запуск: coverage run -m pytest && coverage report.
# simple_func.py
def is_even(x):
return x % 2 == 0
# test_simple.py
def test_is_even():
assert is_even(4) is True
assert is_even(3) is False
Имя Stmts Miss Cover ------------------------------------- simple_func.py 2 0 100%