Как запускать модульные тесты Python со стандартной структурой каталогов
Узнайте стандартный метод запуска модульных тестов Python с типичными структурами каталогов. Узнайте, как использовать `python -m unittest discover` для автоматического решения проблем импорта без изменения PYTHONPATH.
Какой стандартный метод для запуска модульных тестов в Python при использовании типичной структуры тестового каталога?
При организации Python-проекта с общей структурой каталогов, как в следующем примере:
new_project/
antigravity/
antigravity.py
test/
test_antigravity.py
setup.py
и т.д.
Запуск python test_antigravity.py из каталога test не работает, потому что инструкция import antigravity не может найти модуль. Какой рекомендуемый подход для запуска этих тестов без необходимости для пользователей изменять PYTHONPATH или копировать тестовые файлы в другие каталоги?
Я ищу решение, которое позволит мне инструктировать пользователей простой командой: ‘Для запуска модульных тестов выполните X.’
Стандартный метод для запуска юнит-тестов в Python с типичной структурой каталогов тестов — использование команды python -m unittest discover из корневого каталога проекта. Этот подход автоматически добавляет необходимые каталоги в sys.path, позволяя тестовым файлам импортировать модули из основного пакета без необходимости ручного изменения путей или копирования файлов.
Содержание
- Понимание проблемы
- Рекомендуемое решение: Использование интерфейса командной строки unittest
- Альтернативные подходы
- Лучшие практики для структуры проекта Python
- Пошаговое руководство по реализации
Понимание проблемы
При организации Python-проекта с отдельными каталогами для исходного кода и тестов возникает распространенная проблема с импортом. В структуре:
new_project/
antigravity/
antigravity.py
test/
test_antigravity.py
Запуск python test_antigravity.py из каталога test завершается ошибкой, потому что Python не может найти модуль antigravity. Это происходит потому, что каталог тестов не осведомлен о расположении исходного кода проекта в родительском каталоге.
Задача состоит в том, чтобы предоставить пользователям простую и надежную команду для запуска тестов без необходимости:
- Изменять переменные окружения
PYTHONPATH - Копировать тестовые файлы в другие места
- Использовать сложные инструкции импорта
Рекомендуемое решение: Использование интерфейса командной строки unittest
Наиболее надежным и соответствующим стандартам Python решением является использование интерфейса командной строки unittest с методом discover. Этот подход рекомендуется несколькими авторитетными источниками и автоматически обрабатывает разрешение путей.
Стандартная команда
Согласно официальной документации Python, рекомендуемая команда:
python -m unittest discover -s new_project -p "test_*.py"
Для конкретной структуры, о которой вы упомянули:
python -m unittest discover -s . -p "test_*.py"
Эта команда, запущенная из корневого каталога проекта (new_project/), будет:
- Начать обнаружение в текущем каталоге (
-s .) - Найти все файлы, соответствующие шаблону
test_*.py(-p "test_*.py") - Автоматически добавить необходимые каталоги в
sys.path - Выполнить все обнаруженные тесты
Упрощенная версия
Как указано в документации Python, вы также можете использовать упрощенную версию:
python -m unittest discover
При запуске из корневого каталога этот метод автоматически обнаружит тесты в подкаталогах со стандартным соглашением об именовании.
Почему это работает: интерфейс командной строки unittest автоматически добавляет каталог, содержащий тестовые файлы, в sys.path, позволяя тестам импортировать модули из родительского каталога пакета [1, 2, 3].
Альтернативные подходы
Хотя интерфейс командной строки unittest является рекомендуемым подходом, существуют и другие методы:
1. Запуск из корневого каталога с указанием модуля
Вы также можете запускать конкретные тестовые модули с помощью:
python -m unittest new_project.test.test_antigravity
Этот подход работает потому, что Python автоматически добавляет каталог тестового модуля в путь, позволяя использовать относительные импорты [6].
2. Использование метода discover TestLoader
Программно вы можете использовать метод discover TestLoader:
import unittest
import os
loader = unittest.TestLoader()
suite = loader.discover(os.path.join(os.path.dirname(__file__), 'test'))
unittest.TextTestRunner().run(suite)
Этот подход полезен, когда вам нужно интегрировать запуск тестов в более крупное приложение [8].
3. Подход с виртуальным окружением
Некоторые разработчики предпочитают создавать виртуальное окружение, в котором исходный пакет установлен в режиме разработки:
cd new_project
pip install -e .
cd ..
python -m unittest discover -s new_project/test
Этот подход гарантирует, что пакет всегда доступен для импорта, но требует дополнительных шагов настройки.
Лучшие практики для структуры проекта Python
На основе результатов исследования, вот рекомендуемые лучшие практики:
Рекомендации по структуре каталогов
-
Используйте
tests/вместоtest/- Согласно Stack Overflow, использованиеtests/предотвращает конфликт со встроенным модулемtestв стандартной библиотеке Python. -
Сделайте каталог тестов пакетом - Добавьте
__init__.pyв каталог тестов, чтобы он стал правильным Python-пакетом [2, 4]. -
Следуйте соглашениям об именовании - Используйте префикс
test_для тестовых файлов и суффикс_test[3, 10].
Пример структуры
new_project/
antigravity/
__init__.py
antigravity.py
tests/
__init__.py
test_antigravity.py
setup.py
README.md
Запуск тестов в разных средах
Для разных сценариев хорошо работают следующие команды:
- Из корневого каталога проекта:
python -m unittest discover - С конкретным шаблоном:
python -m unittest discover -s . -p "test_*.py" - Для конкретного теста:
python -m unittest tests.test_antigravity - Изнутри проекта:
python -m unittest discover -s .
Пошаговое руководство по реализации
Настройка структуры проекта
- Создайте структуру каталогов проекта:
mkdir new_project
cd new_project
mkdir antigravity tests
- Создайте структуру пакета:
# В antigravity/
touch __init__.py
touch antigravity.py
# В tests/
touch __init__.py
touch test_antigravity.py
- Напишите ваш тестовый файл (
tests/test_antigravity.py):
import unittest
import sys
import os
# Добавьте родительский каталог в sys.path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import antigravity
class TestAntigravity(unittest.TestCase):
def test_antigravity_exists(self):
self.assertTrue(hasattr(antigravity, 'antigravity'))
# Добавьте больше тестовых методов здесь
if __name__ == '__main__':
unittest.main()
Запуск тестов
- Из корневого каталога проекта (
new_project/):
python -m unittest discover
- С указанием конкретного каталога и шаблона:
python -m unittest discover -s . -p "test_*.py"
- Для конкретного тестового файла:
python -m unittest tests.test_antigravity
Создание псевдонима оболочки для простого тестирования
Чтобы предоставить пользователям простую команду, как запрошено, вы можете создать псевдоним оболочки в документации проекта:
# Добавьте это в ~/.bashrc или в инструкции, специфичные для проекта
alias run_tests="python -m unittest discover -s . -p 'test_*.py'"
Затем пользователи могут просто запустить:
run_tests
Альтернатива: Интеграция с setup.py
Для более профессиональной настройки вы можете добавить команды тестов в ваш setup.py:
from setuptools import setup
setup(
name="new_project",
# ... другие параметры настройки
cmdclass={
'test': unittest.TestCommand,
},
)
Это позволяет пользователям запускать тесты с помощью:
python setup.py test
Источники
- Running unittest with typical test directory structure - Stack Overflow
- Typical Directory structure for python tests · GitHub
- unittest — Unit testing framework - Python Documentation
- Structuring Unit Tests in Python - Plain English
- Typical directory structure for running tests using unittest in Python - GeeksforGeeks
- Where do the Python unit tests go? - Stack Overflow
- Run Unittest from a Python program via a command-line option - Stack Overflow
- Run Unittest in Python: Organizing Code & Running Unittest - Python Tutorial
- Understanding Unit Testing in Python - BrowserStack
- How do I write Python unit tests for scripts in my bin directory - Stack Overflow
Заключение
Стандартный метод для запуска юнит-тестов в Python с типичной структурой каталогов тестов — использование команды python -m unittest discover из корневого каталога проекта. Этот подход:
- Автоматически обрабатывает разрешение путей без необходимости ручного изменения
PYTHONPATH - Следует стандартным соглашениям Python для обнаружения и выполнения тестов
- Работает с рекомендуемой структурой проекта с отдельными каталогами для исходного кода и тестов
- Предоставляет простую и запоминающуюся команду, которую пользователи могут легко использовать
Для пользователей вашего проекта инструкция должна быть: “Чтобы запустить юнит-тесты, перейдите в корневой каталог проекта и выполните python -m unittest discover.”
Это решение надежно, широко adopted в сообществе Python и последовательно работает на разных операционных системах и версиях Python. Для более сложных сценариев вы можете расширить этот подход с использованием конкретных шаблонов или интегрировать команды тестирования в конфигурацию настройки вашего проекта.