Тестирование в Python
unittest — стандартная библиотека
python
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_positive_numbers(self):
self.assertEqual(add(2, 3), 5)
def test_negative_numbers(self):
self.assertEqual(add(-1, -1), -2)
def test_zero(self):
self.assertEqual(add(0, 0), 0)
if __name__ == "__main__":
unittest.main()Методы assert
python
class TestExamples(unittest.TestCase):
def test_assertions(self):
self.assertEqual(1 + 1, 2)
self.assertNotEqual(1, 2)
self.assertTrue(True)
self.assertFalse(False)
self.assertIsNone(None)
self.assertIsNotNone("value")
self.assertIn(3, [1, 2, 3])
self.assertNotIn(4, [1, 2, 3])
self.assertIsInstance("hello", str)
self.assertAlmostEqual(3.14, 3.14159, places=1)
def test_exception(self):
with self.assertRaises(ZeroDivisionError):
1 / 0setUp и tearDown
python
class TestDatabase(unittest.TestCase):
def setUp(self):
"""Выполняется перед каждым тестом."""
self.db = {"users": []}
def tearDown(self):
"""Выполняется после каждого теста."""
self.db.clear()
def test_add_user(self):
self.db["users"].append("Иван")
self.assertEqual(len(self.db["users"]), 1)
def test_empty_db(self):
self.assertEqual(len(self.db["users"]), 0)pytest — популярный фреймворк
Установка
bash
pip install pytestБазовые тесты
python
# test_math.py
def add(a, b):
return a + b
def test_add_positive():
assert add(2, 3) == 5
def test_add_negative():
assert add(-1, -1) == -2
def test_add_strings():
assert add("hello ", "world") == "hello world"bash
# Запуск тестов
pytest
pytest test_math.py
pytest -v # подробный выводПараметризованные тесты
python
import pytest
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5),
(-1, 1, 0),
(0, 0, 0),
(100, 200, 300),
])
def test_add(a, b, expected):
assert add(a, b) == expectedФикстуры
python
import pytest
@pytest.fixture
def sample_list():
return [1, 2, 3, 4, 5]
@pytest.fixture
def db_connection():
conn = create_connection()
yield conn # тест выполняется здесь
conn.close() # очистка
def test_list_length(sample_list):
assert len(sample_list) == 5
def test_list_sum(sample_list):
assert sum(sample_list) == 15Проверка исключений
python
import pytest
def divide(a, b):
if b == 0:
raise ValueError("Делитель не может быть нулём")
return a / b
def test_divide_by_zero():
with pytest.raises(ValueError, match="нулём"):
divide(10, 0)Маркеры
python
import pytest
@pytest.mark.slow
def test_heavy_computation():
result = sum(range(10_000_000))
assert result > 0
@pytest.mark.skip(reason="Ещё не реализовано")
def test_future_feature():
pass
@pytest.mark.skipif(
condition=True,
reason="Не поддерживается на данной платформе"
)
def test_platform_specific():
passbash
# Запуск только определённых маркеров
pytest -m slow
pytest -m "not slow"Mock — подмена объектов
python
from unittest.mock import Mock, patch, MagicMock
# Простой мок
mock_api = Mock()
mock_api.get_user.return_value = {"name": "Иван"}
print(mock_api.get_user(1)) # {"name": "Иван"}
# patch — подмена модулей
def get_data():
import requests
response = requests.get("https://api.example.com/data")
return response.json()
@patch("requests.get")
def test_get_data(mock_get):
mock_get.return_value.json.return_value = {"status": "ok"}
result = get_data()
assert result == {"status": "ok"}
mock_get.assert_called_once()Запуск тестов
bash
# pytest
pytest # все тесты
pytest -v # подробный вывод
pytest -x # остановиться на первой ошибке
pytest --tb=short # краткий traceback
pytest -k "test_add" # тесты по имени
pytest --cov=mypackage # покрытие кода (нужен pytest-cov)
# unittest
python -m unittest discover
python -m unittest test_module.TestClass.test_method