Использование pytest со слоем src

pytest рекомендует включить дополнительный каталог для разделения исходного кода внутри проекта:

my_package
├── src  # <-- no __init__.py on this layer
│   └── my_package
│       ├── __init__.py
│       └── util_module
│           ├── __init__.py
│           └── utils.py
└── tests
    ├── __init__.py
    └── test_util_module
        ├── __init__.py
        └── test_utils.py

К сожалению, они ничего не говорят[1] о том, как должен работать импорт в тестовом коде в таком случае, который отлично работает для моей IDE в этот наивный пример[2], но вызывает следующую ошибку с pytest:

my_package $ pytest

====================== test session starts ======================
platform linux -- Python 3.6.4, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/user/workspace/my_package, inifile:
collected 0 items / 1 errors     
                                                                                                                                                                      
============================ ERRORS =============================
___ ERROR collecting tests/test_util_module/test_utils.py ___
ImportError while importing test module '/home/user/workspace/my_package/tests/test_util_module/test_utils.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_util_module/test_utils.py:1: in <module>
    from test.test_module.some_file import starify
E   ModuleNotFoundError: No module named 'my_package.util_module'
!!!! Interrupted: 1 errors during collection !!!!!

Я могу решить эту проблему, изменив импорт теста на from src.my_package.util_module.utils import starify, но затем моя IDE жалуется на то, что часть src избыточна, поэтому я бы хотел ее исключить.


[1]: Это уже не так. Начиная с версии 3.7.3, pytest рекомендует редактируемую установку, также представленную в ответе @hoefling в верхней части его рекомендации.

[2]: установка virtualenv env -p python3.6; source env/bin/activate; pip install pytest


person Arne    schedule 03.05.2018    source источник
comment
Являются ли ваши тестовые каталоги обычными каталогами или это пакеты (содержащие файл __init__.py)?   -  person Tom Dalton    schedule 03.05.2018
comment
@TomDalton Каждый каталог, кроме корневого каталога и каталога src, является пакетом. Секунду, я публикую tree .   -  person Arne    schedule 03.05.2018
comment
Если вы экспортируете PYTHONPATH=".:src/" перед запуском тестов, это что-то изменит?   -  person Tom Dalton    schedule 03.05.2018
comment
(Я предполагаю, что вы запускаете тесты из корневого каталога)   -  person Tom Dalton    schedule 03.05.2018
comment
например test $ pytest должно быть my_package $ pytest?   -  person Tom Dalton    schedule 03.05.2018
comment
@TomDalton да, я переименовываю пример прямо сейчас ... это было немного запутанно, я думаю. Кроме того, экспорт PYTHONPATH также работает   -  person Arne    schedule 03.05.2018
comment
Теперь вывод pytest не соответствует вашему дереву каталогов: D   -  person Tom Dalton    schedule 03.05.2018
comment
Хорошо, я воспроизвел структуру и все, она воспроизводится так, как сейчас в посте. Экспорт PYTHONPATH решает проблему, и это, безусловно, лучше, чем добавление src. перед импортом всех наборов тестов, но я надеюсь на более чистое решение, которое сделает репозиторий доступным для тестирования, как сейчас.   -  person Arne    schedule 03.05.2018
comment
Вы установили my_package, т.е. содержит ли он setup.py?   -  person Nils Werner    schedule 03.05.2018
comment
@NilsWerner Нет и нет. Должен ли я всегда делать это перед тестированием? Я бы предпочел запустить модульные тесты перед сборкой в ​​CI, но могу ошибаться.   -  person Arne    schedule 03.05.2018
comment
Да, конечно, вам: 1) нужно собрать код, чтобы протестировать его. 2) сделать пакет importактивным, установив его   -  person Nils Werner    schedule 03.05.2018
comment
конечно, вам: 1) нужно собрать код, чтобы протестировать его. - В общем случае это неверно, и для многих людей (в том числе и для меня) нежелательно   -  person Tom Dalton    schedule 03.05.2018
comment
И, конечно же, вы: ... 2) делаете пакет доступным для импорта, установив его, пакеты можно импортировать, не устанавливая их где-либо, если путь поиска пакетов python настроен правильно (например, путем установки pythonpath или других трюков).   -  person Tom Dalton    schedule 03.05.2018
comment
@TomDalton И правильный способ правильно настроить путь поиска - это ... (барабанная дробь) ... установка пакета!   -  person wim    schedule 03.05.2018


Ответы (2)


Настройка PYTHONPATH (как предлагается в комментариях) — это одна из возможностей решить проблему импорта. Другой добавляет пустой файл conftest.py в каталог src:

$ touch src/conftest.py

а pytest добавит src к sys.path. Это простой способ заставить pytest добавить кодовую базу в sys.path.

Однако макет src обычно выбирается, когда вы собираетесь создать дистрибутив, например. предоставление setup.py с (в данном случае) явным указанием каталога корневого пакета:

from setuptools import find_packages, setup


setup(
    ...
    package_dir={'': 'src'},
    packages=find_packages(where='src'),
    ...
)

и установка пакета в режиме разработки (через python setup.py develop или pip install --editable .), пока вы еще его разрабатываете. Таким образом, ваш пакет my_package правильно интегрируется в структуру пакетов сайта Python, и нет необходимости возиться с PYTHONPATH.

person hoefling    schedule 03.05.2018
comment
Кроме того, у SO есть отличный ответ по этой теме. - person hoefling; 03.05.2018
comment
Я протестировал оба решения и оба работают =) спасибо за помощь! - person Arne; 03.05.2018

Обновления PYTHONPATH у меня не работали при использовании действий github (известная проблема). Вместо этого у меня сработало использование этой установки pytest-pythonpath с файлом pytest.ini:

pip install pytest-pythonpath # accompany with python_path in pytest.ini, so PYTHONPATH is updated with location for modules under test

При этом базовая команда «pytest» с радостью нашла все тесты в подкаталогах и нашла тестируемые модули на основе моего pytest.ini (установленного для соответствия исходным папкам в pycharm)

person Patrick Boundy    schedule 27.09.2020