Тестирование
pytest — современный тестовый фреймворк
Установка: pip install pytest
# test_calc.py
def add(a, b):
return a + b # возврат значения
# Имя теста начинается с test_
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
# Запуск
pytest
pytest test_calc.py
pytest test_calc.py::test_add
pytest -v
pytest -k "add"
pytest -x
pytest --tb=short
Фикстуры (fixtures)
import pytest # импорт тестового фреймворка
@pytest.fixture # фикстура pytest
def user_data():
return {"name": "Анна", "age": 30} # возврат значения
@pytest.fixture # фикстура pytest
def database():
# Setup
db = create_test_database() # присваивание
yield db # генерация значения
# Teardown
db.drop()
def test_user_name(user_data):
assert user_data["name"] == "Анна"
def test_user_age(user_data):
assert user_data["age"] == 30
Параметризация
import pytest # импорт тестового фреймворка
@pytest.mark.parametrize("a, b, expected", [ # параметризация теста
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(100, -50, 50),
])
def test_add(a, b, expected):
assert a + b == expected
# Несколько параметров
@pytest.mark.parametrize("a", [1, 2]) # параметризация теста
@pytest.mark.parametrize("b", [3, 4]) # параметризация теста
def test_product(a, b):
pass # 4 комбинации
Моки (unittest.mock)
from unittest.mock import Mock, patch # импорт модуля
import requests # импорт модуля регулярных выражений
# Mock объект
mock_response = Mock() # присваивание
mock_response.json.return_value = {"id": 1, "name": "Анна"}
mock_response.status_code = 200
# patch — замена в контексте
@patch("requests.get") # подмена объекта на mock
def test_fetch(mock_get):
mock_get.return_value = mock_response
result = fetch_user(1) # присваивание
assert result["name"] == "Анна"
# Проверка вызова
mock_get.assert_called_once_with("https://api.example.com/users/1") # проверка вызова с аргументами
unittest — встроенный модуль
import unittest # импорт встроенного тестового модуля
class TestMath(unittest.TestCase):
def setUp(self): # подготовка перед каждым тестом
"""Выполняется перед каждым тестом"""
self.data = [1, 2, 3] # обращение к атрибуту экземпляра
def test_sum(self):
self.assertEqual(sum(self.data), 6) # обращение к атрибуту экземпляра
def test_max(self):
self.assertEqual(max(self.data), 3) # обращение к атрибуту экземпляра
def test_in(self):
self.assertIn(2, self.data) # обращение к атрибуту экземпляра
if __name__ == "__main__": # условие
unittest.main()
Проверки (assertions)
assert result == expected
assert result != wrong
assert result is None
assert result is not None
assert value in collection
assert len(items) > 0 # длина
assert "error" not in response.text
assert response.status_code == 200
# pytest предоставляет
pytest.approx(3.14159, 0.001) # сравнение float с погрешностью
pytest.raises(ValueError) # проверка ожидаемого исключения
pytest.warns(UserWarning) # проверка ожидаемого предупреждения
Проверка исключений
import pytest # импорт тестового фреймворка
def test_raises():
with pytest.raises(ValueError, match="деление на ноль"): # контекстный менеджер
divide(10, 0)
def test_raises_no_match():
with pytest.raises(ZeroDivisionError): # контекстный менеджер
1 / 0
Покрытие кода (coverage)
# Установка
pip install pytest-cov
# Запуск с покрытием
pytest --cov=my_module --cov-report=html
pytest --cov=my_module --cov-report=term-missing
# Минимальный порог
pytest --cov=my_module --cov-fail-under=80