Я новичок в модульном тестировании и пытаюсь создать свой первый файл модульных тестов в Python 3. Поэтому у меня есть следующая действительно элементарная структура папок, просто имитирующая онлайн-курс.
D:\Projects\Projects\unit_testing_course # parent dir absolute path
unit_testing_course/ # root/parent folder
first_project.py # has a function called avg()
tests/
test_first_project.py # I want to import avg() into this file
test_first_project.py - это файл, который я использую для модульного тестирования, и я хочу импортировать функцию avg() из first_project.py, который находится в родительском каталоге над ним.
У меня Windows 10, у меня открыт git bash по следующему пути: '/d/Projects/Projects/unit_testing_course' (т.е. родительский каталог, содержащий first_project.py, модуль/функцию, которую я пытаюсь импортировать в test_first_project.py файл в дочернем каталоге tests). Я продолжаю выполнять python tests/test_first_project.py
Я быстро обнаружил, что не могу использовать что-то вроде "from.. import first_project" или "from.. import avg", что приводит к сообщению об ошибке "ValueError: попытка относительного импорта за пределы пакета верхнего уровня".
Таким образом, читая документацию, я получаю, что и from, и import являются инструкциями, предназначенными для работы с модулями или пакетами. https://docs.python.org/3/tutorial/modules.html
"В Python есть способ поместить определения в файл и использовать их в сценарии или в интерактивном экземпляре интерпретатора. Такой файл называется модулем; определения из модуля можно импортировать в другие модули или в основной модуль ( набор переменных, к которым у вас есть доступ в скрипте, выполняемом на верхнем уровне и в режиме калькулятора).
Модуль - это файл, содержащий определения и операторы Python. Имя файла - это имя модуля с добавленным суффиксом .py. Внутри модуля имя модуля (в виде строки) доступно как значение глобальной переменной __name__. "
Похоже, что для python 3 каждый файл .py является модулем, а имя модуля - это, по сути, имя файла .py без расширения .py в конце. И, похоже, я пытаюсь импортировать модуль из родительского каталога файла test_first_project.py.
эта ссылка на документацию полезна для объяснения сценария, в котором у вас есть модуль в текущем каталоге, из которого вы запускаете оболочку программы /python, и вы просто пытаетесь импортировать функцию из этого модуля в эту программу.
Но в этом случае кажется, что нам нужно сказать Python, что нужно искать модуль с именем 'first_project' в определенном каталоге, родительском каталоге файла test_first_project.py. Я посмотрел раздел о путях поиска модулей, https://docs.python.org/3/tutorial/modules.html#the-module-search-path
Когда импортируется модуль с именем "спам", интерпретатор сначала ищет встроенный модуль с таким именем. Если он не найден, он ищет файл с именем spam.py в списке каталогов, заданных переменной sys.path. После инициализации программы на Python могут изменять sys.path. Каталог, содержащий выполняемый скрипт, помещается в начало пути поиска, перед стандартным путем к библиотеке.
Тогда я попробовал...
import sys
import os
p_dir_path = os.path.abspath('../')
sys.path.append(p_dir_path)
from first_project import avg
Который до сих пор получает то же сообщение об ошибке "ValueError: попытка относительного импорта за пределы пакета верхнего уровня". Я надеялся, что изменение sys.path программно может изменить ситуацию...
Так что же мне нужно сделать для того, чтобы импортировать модуль из родительского каталога? Или... это невозможно сделать в Python? Нужно ли мне использовать пакет вместо модуля (т.е. мне нужно создать init.py в моем родительском каталоге)?
Я видел другие вопросы и сообщения о stackoverflow о попытке импортировать файл в другой каталог и другие случаи, но имитация синтаксиса этих вопросов мне не помогла, и я думаю, что потратил слишком много времени на это. Я также уверен, что я не единственный человек, который хотел создать модульные тесты и был отвлечен проблемами с инструкциями импорта, модулями и пакетами.
Вы должны установить переменную PYTHONPATH
соответствии с вашим проектом. В unit_testing_course
, запустите
export PYTHONPATH=$(pwd)
в твоей раковине. И рассмотрим следующий код:
first_project.py
def avg(l):
return sum(l)/len(l) if len(l) > 0 else 0
tests/test_first_project.py
import unittest
from first_project import avg
class Test(unittest.TestCase):
...
tests/__init__.py
from .test_first_project import *
запуск python -m unittest tests
будет работать как python -m unittest tests
(при условии, что python
указывает на желаемую версию python). Вы также можете использовать virtualenv
и изменить его venv/bin/activate
чтобы автоматически выполнить эту настройку пути. Когда ваш проект продолжает расти, я рекомендую иметь в базе две отдельные директории - одну для самого проекта и одну для тестов. Затем используйте относительный импорт в каждом соответственно. Это позволит вашему проекту быть гибким, если вы решите упаковать его или использовать как подмодуль или что-то вроде этого.
python tests/test_first_project.py
или простоpython -m unittest
. Возможно, понадобитсяtests/__init__.py
.