Ответ
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
: Позволяет писать тесты как обычные функции или методы, используя стандартный операторassert
Python. Это делает тесты более читаемыми, лаконичными и интуитивно понятными, так как не требует изучения специфических методов.# 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
остается надежным выбором для базового модульного тестирования, особенно в проектах, где он уже используется или когда требуется строгая совместимость со стандартной библиотекой.