Короткий ответ
unittest.TestCase требует наследования от базового класса и использует методы assertEqual/assertTrue и т.п., а pytest позволяет писать обычные функции с простым assert и подключать зависимости через фикстуры вместо setUp/tearDown.
Как это работает подробнее
unittest — часть стандартной библиотеки, тесты оформляются как методы класса, унаследованного от unittest.TestCase, с методами setUp/tearDown для подготовки и очистки состояния класса. Pytest не требует наследования: тест — это обычная функция, а подготовка данных делается через фикстуры, которые можно комбинировать, переиспользовать между разными модулями и параметризовать гибче, чем атрибуты класса в unittest.
Пример кода
testing_example_294.py
import unittest
class TestMath(unittest.TestCase):
def setUp(self):
self.value = 10
def test_double(self):
self.assertEqual(self.value * 2, 20)
# Эквивалент в стиле pytest:
def test_double_pytest():
value = 10
assert value * 2 == 20Что использовать на практике
- Практика. Pytest умеет запускать и обычные unittest-тесты, поэтому миграция возможна постепенно, модуль за модулем, без необходимости переписывать весь проект сразу. Многие команды выбирают pytest из-за более читаемых сообщений об ошибках assert, параметризации (@pytest.mark.parametrize) и богатой экосистемы плагинов (pytest-cov, pytest-asyncio, pytest-mock), которых у чистого unittest нет из коробки.
Подводные камни
- Риск. Смешивать стили непоследовательно в одном модуле без причины, что усложняет чтение и ревью кода новым участникам команды. Использовать assertEqual в pytest-тестах по привычке, теряя преимущество подробного вывода обычного assert, который сразу показывает конкретное расхождение значений.