Другое

Как запускать модульные тесты 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, позволяя тестовым файлам импортировать модули из основного пакета без необходимости ручного изменения путей или копирования файлов.


Содержание


Понимание проблемы

При организации Python-проекта с отдельными каталогами для исходного кода и тестов возникает распространенная проблема с импортом. В структуре:

new_project/
    antigravity/
        antigravity.py
    test/
        test_antigravity.py

Запуск python test_antigravity.py из каталога test завершается ошибкой, потому что Python не может найти модуль antigravity. Это происходит потому, что каталог тестов не осведомлен о расположении исходного кода проекта в родительском каталоге.

Задача состоит в том, чтобы предоставить пользователям простую и надежную команду для запуска тестов без необходимости:

  • Изменять переменные окружения PYTHONPATH
  • Копировать тестовые файлы в другие места
  • Использовать сложные инструкции импорта

Рекомендуемое решение: Использование интерфейса командной строки unittest

Наиболее надежным и соответствующим стандартам Python решением является использование интерфейса командной строки unittest с методом discover. Этот подход рекомендуется несколькими авторитетными источниками и автоматически обрабатывает разрешение путей.

Стандартная команда

Согласно официальной документации Python, рекомендуемая команда:

bash
python -m unittest discover -s new_project -p "test_*.py"

Для конкретной структуры, о которой вы упомянули:

bash
python -m unittest discover -s . -p "test_*.py"

Эта команда, запущенная из корневого каталога проекта (new_project/), будет:

  • Начать обнаружение в текущем каталоге (-s .)
  • Найти все файлы, соответствующие шаблону test_*.py (-p "test_*.py")
  • Автоматически добавить необходимые каталоги в sys.path
  • Выполнить все обнаруженные тесты

Упрощенная версия

Как указано в документации Python, вы также можете использовать упрощенную версию:

bash
python -m unittest discover

При запуске из корневого каталога этот метод автоматически обнаружит тесты в подкаталогах со стандартным соглашением об именовании.

Почему это работает: интерфейс командной строки unittest автоматически добавляет каталог, содержащий тестовые файлы, в sys.path, позволяя тестам импортировать модули из родительского каталога пакета [1, 2, 3].


Альтернативные подходы

Хотя интерфейс командной строки unittest является рекомендуемым подходом, существуют и другие методы:

1. Запуск из корневого каталога с указанием модуля

Вы также можете запускать конкретные тестовые модули с помощью:

bash
python -m unittest new_project.test.test_antigravity

Этот подход работает потому, что Python автоматически добавляет каталог тестового модуля в путь, позволяя использовать относительные импорты [6].

2. Использование метода discover TestLoader

Программно вы можете использовать метод discover TestLoader:

python
import unittest
import os

loader = unittest.TestLoader()
suite = loader.discover(os.path.join(os.path.dirname(__file__), 'test'))
unittest.TextTestRunner().run(suite)

Этот подход полезен, когда вам нужно интегрировать запуск тестов в более крупное приложение [8].

3. Подход с виртуальным окружением

Некоторые разработчики предпочитают создавать виртуальное окружение, в котором исходный пакет установлен в режиме разработки:

bash
cd new_project
pip install -e .
cd ..
python -m unittest discover -s new_project/test

Этот подход гарантирует, что пакет всегда доступен для импорта, но требует дополнительных шагов настройки.


Лучшие практики для структуры проекта Python

На основе результатов исследования, вот рекомендуемые лучшие практики:

Рекомендации по структуре каталогов

  1. Используйте tests/ вместо test/ - Согласно Stack Overflow, использование tests/ предотвращает конфликт со встроенным модулем test в стандартной библиотеке Python.

  2. Сделайте каталог тестов пакетом - Добавьте __init__.py в каталог тестов, чтобы он стал правильным Python-пакетом [2, 4].

  3. Следуйте соглашениям об именовании - Используйте префикс 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 .

Пошаговое руководство по реализации

Настройка структуры проекта

  1. Создайте структуру каталогов проекта:
bash
mkdir new_project
cd new_project
mkdir antigravity tests
  1. Создайте структуру пакета:
bash
# В antigravity/
touch __init__.py
touch antigravity.py

# В tests/
touch __init__.py
touch test_antigravity.py
  1. Напишите ваш тестовый файл (tests/test_antigravity.py):
python
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()

Запуск тестов

  1. Из корневого каталога проекта (new_project/):
bash
python -m unittest discover
  1. С указанием конкретного каталога и шаблона:
bash
python -m unittest discover -s . -p "test_*.py"
  1. Для конкретного тестового файла:
bash
python -m unittest tests.test_antigravity

Создание псевдонима оболочки для простого тестирования

Чтобы предоставить пользователям простую команду, как запрошено, вы можете создать псевдоним оболочки в документации проекта:

bash
# Добавьте это в ~/.bashrc или в инструкции, специфичные для проекта
alias run_tests="python -m unittest discover -s . -p 'test_*.py'"

Затем пользователи могут просто запустить:

bash
run_tests

Альтернатива: Интеграция с setup.py

Для более профессиональной настройки вы можете добавить команды тестов в ваш setup.py:

python
from setuptools import setup

setup(
    name="new_project",
    # ... другие параметры настройки
    cmdclass={
        'test': unittest.TestCommand,
    },
)

Это позволяет пользователям запускать тесты с помощью:

bash
python setup.py test

Источники

  1. Running unittest with typical test directory structure - Stack Overflow
  2. Typical Directory structure for python tests · GitHub
  3. unittest — Unit testing framework - Python Documentation
  4. Structuring Unit Tests in Python - Plain English
  5. Typical directory structure for running tests using unittest in Python - GeeksforGeeks
  6. Where do the Python unit tests go? - Stack Overflow
  7. Run Unittest from a Python program via a command-line option - Stack Overflow
  8. Run Unittest in Python: Organizing Code & Running Unittest - Python Tutorial
  9. Understanding Unit Testing in Python - BrowserStack
  10. 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. Для более сложных сценариев вы можете расширить этот подход с использованием конкретных шаблонов или интегрировать команды тестирования в конфигурацию настройки вашего проекта.

Авторы
Проверено модерацией
Модерация