Ответ
unittest — это встроенный в Python фреймворк для модульного тестирования, являющийся частью стандартной библиотеки. pytest — популярный сторонний фреймворк, предлагающий более современный и гибкий подход к написанию тестов. Оба используются для написания и запуска тестов, но имеют существенные различия в синтаксисе, функциональности и экосистеме.
1. Синтаксис написания тестов
-
unittest: Требует создания классов, наследующихся отunittest.TestCase, и использования специальных методовassert*(например,assertEqual(),assertTrue()). Это может приводить к более многословному коду.import unittest class TestMath(unittest.TestCase): def test_addition(self): self.assertEqual(1 + 1, 2) def test_subtraction(self): self.assertTrue(5 - 3 == 2) -
pytest: Позволяет писать тесты как обычные функции или методы, используя стандартный операторassertPython. Это делает тесты более читаемыми, лаконичными и интуитивно понятными, так как не требует изучения специфических методов.# test_math.py def test_addition(): assert 1 + 1 == 2 def test_subtraction(): assert 5 - 3 == 2
2. Фикстуры (Fixtures)
-
unittest: Использует методыsetUp()иtearDown()(илиsetUpClass/tearDownClass) для подготовки и очистки тестового окружения. Они привязаны к жизненному циклу класса или метода и могут быть менее гибкими для переиспользования.import unittest class TestDatabase(unittest.TestCase): def setUp(self): # Подключение к БД перед каждым тестом self.db_conn = connect_to_db() def tearDown(self): # Закрытие соединения после каждого теста self.db_conn.close() def test_query(self): result = self.db_conn.execute("SELECT 1") self.assertEqual(result, 1) -
pytest: Предлагает более гибкую и мощную систему фикстур с помощью декоратора@pytest.fixture. Фикстуры могут быть функциями, возвращающими данные, и внедряться в тесты по имени. Это позволяет легко переиспользовать логику подготовки/очистки, управлять их областью видимости (функция, модуль, сессия) и создавать сложные зависимости.import pytest @pytest.fixture def db_connection(): # Подготовка ресурса (например, подключение к БД) conn = connect_to_db() yield conn # Тесты, использующие эту фикстуру, выполняются здесь # Очистка ресурса после выполнения тестов conn.close() def test_query(db_connection): result = db_connection.execute("SELECT 1") assert result == 1
3. Параметризация тестов
unittest: Параметризация сложнее, часто требует использованияsubTest(для Python 3.4+) или внешних библиотек, что может усложнить код.-
pytest: Встроенная и мощная поддержка параметризации с помощью декоратора@pytest.mark.parametrize, что позволяет легко запускать один и тот же тест с разными наборами входных данных, значительно сокращая дублирование кода.import pytest @pytest.mark.parametrize("a, b, expected", [ (1, 1, 2), (2, 3, 5), (0, 0, 0), ]) def test_addition(a, b, expected): assert a + b == expected
4. Отчеты и плагины
unittest: Генерирует базовые отчеты. Расширение функциональности часто требует написания кастомных тестовых раннеров.pytest: Генерирует более информативные и читаемые отчеты по умолчанию, включая подробную информацию о сбоях. Имеет богатую экосистему плагинов (например,pytest-covдля покрытия кода,pytest-xdistдля параллельного выполнения,pytest-mockдля моков), что значительно расширяет его возможности и гибкость.
Вывод
pytest часто предпочтительнее для новых проектов благодаря своей простоте, гибкости, мощной системе фикстур и обширной экосистеме плагинов, что способствует написанию более чистого и эффективного тестового кода. unittest остается надежным выбором для базового модульного тестирования, особенно в проектах, где он уже используется или когда требуется строгая совместимость со стандартной библиотекой.