如何将要测试的模块导入到测试模块中
How to import the module to test into the test module
问题
我的项目有一个目录结构,它遵循 Python 包的标准,因为它是使用这个 cookiecutter 模板创建的:
https://github.com/audreyr/cookiecutter-pypackage#quickstart
目录结构为
project_name
├── project_name
│ ├── __init__.py
│ └── module1.py
└── tests
└── test_module1.py
test_module1.py
的第一行代码是:
from project_name import module1
但是我得到了 ModuleNotFoundError: No module named 'project_name'
.
根据我的理解,这应该有效,因为名为 project_name
的文件夹是一个包,由 __init__.py
文件的存在确保。
我一直无法理解这样的导入是如何工作的。对于我的项目,我总是将我的测试放在与要测试的模块相同的文件夹中。我知道这是不好的做法,但这是让模块真正导入的唯一方法。
我已经尝试过的
我尝试将包含 __init__.py
文件的文件夹重命名为其他名称,然后导入,因为我认为这可能与名称为 [=17 的父文件夹和子文件夹有关=].这没有用,同样的错误。
我还尝试通过在其中创建一个 __init.py__
文件将测试文件夹变成一个包,即使 Cookiecutter 模板没有那个。
我在很多地方读到不鼓励将测试文件夹放入包中,但有些人建议采用这种结构。那也不管用。
我已经彻底搜索了这个看似非常标准的问题的解决方案,一些链接在这里:
- https://gist.github.com/tasdikrahman/2bdb3fb31136a3768fac
- Importing modules from parent folder
- https://alex.dzyoba.com/blog/python-import/
- Sibling package imports
- Python imports for tests using nose - what is best practice for imports of modules above current package
我最后一次尝试是用 Cookiecutter 启动一个项目,这样一开始一切都会正确设置。但是,我仍然得到 ModuleNotFoundError
。
我不要的
我不想修改 sys.path
正如许多答案似乎暗示的那样。对于这种常见问题,必须有更清洁的方法。
我做错了什么?
编辑一些额外的信息(参见来自@Nicholas 的问题):
__init__.py
的内容是
# -*- coding: utf-8 -*-
"""Top-level package for project_name."""
__author__ = """my_name"""
__email__ = 'my_email'
__version__ = '0.1.0'
由 Cookiecutter 模板生成。
在 test_module1
中,我在 ModuleNotFoundError
发生之前添加了以下内容:
import sys
import os
print(sys.path)
print(os.getcwd())
sys.path
打印一个列表,其中第一个元素是 tests
目录。
['c:\Users\...\project_name\tests',
'C:\Users\...\Miniconda3\python37.zip',
'C:\Users\...\Miniconda3\DLLs', 'C:\Users\...\Miniconda3\lib',
'C:\Users\...\Miniconda3',
'C:\Users\...\Miniconda3\lib\site- packages',
'C:\Users\...\Miniconda3\lib\site-packages\win32',
'C:\Users\...\Miniconda3\lib\site-packages\win32\lib',
'C:\Users\...\Miniconda3\lib\site-packages\Pythonwin']
我不知道第一个元素中的小写 'c' 是否重要。
os.getcwd()
打印根目录 'c:\Users\....\project_name'
。还有一个小写的'c'。
您应该创建一个虚拟环境并安装项目,以便测试模块正确解析导入语句。
在项目根目录,即包含子目录project_name
和子目录tests
的目录project_name
,创建一个setup.py
(或pyproject.toml
) 包元数据文件。有关该部分的详细信息,请参阅 here。
从现在包含安装程序 (setup.py
) 的同一项目根目录,创建并激活一个 venv 并安装您的项目:
python3 -m venv .venv
source .venv/bin/activatate # linux/macOS
# .\Scripts\activate.bat # windows
pip install --editable .
pip install pytest
pytest
如果出于某种原因你不想为你的项目创建安装程序,你可以 运行 像这样从项目目录中进行 pytest:
python3 -m pytest
与裸 pytest
命令不同,这会将当前工作目录添加到 sys.path
允许在测试中解析导入语句。
问题
我的项目有一个目录结构,它遵循 Python 包的标准,因为它是使用这个 cookiecutter 模板创建的: https://github.com/audreyr/cookiecutter-pypackage#quickstart
目录结构为
project_name
├── project_name
│ ├── __init__.py
│ └── module1.py
└── tests
└── test_module1.py
test_module1.py
的第一行代码是:
from project_name import module1
但是我得到了 ModuleNotFoundError: No module named 'project_name'
.
根据我的理解,这应该有效,因为名为 project_name
的文件夹是一个包,由 __init__.py
文件的存在确保。
我一直无法理解这样的导入是如何工作的。对于我的项目,我总是将我的测试放在与要测试的模块相同的文件夹中。我知道这是不好的做法,但这是让模块真正导入的唯一方法。
我已经尝试过的
我尝试将包含 __init__.py
文件的文件夹重命名为其他名称,然后导入,因为我认为这可能与名称为 [=17 的父文件夹和子文件夹有关=].这没有用,同样的错误。
我还尝试通过在其中创建一个 __init.py__
文件将测试文件夹变成一个包,即使 Cookiecutter 模板没有那个。
我在很多地方读到不鼓励将测试文件夹放入包中,但有些人建议采用这种结构。那也不管用。
我已经彻底搜索了这个看似非常标准的问题的解决方案,一些链接在这里:
- https://gist.github.com/tasdikrahman/2bdb3fb31136a3768fac
- Importing modules from parent folder
- https://alex.dzyoba.com/blog/python-import/
- Sibling package imports
- Python imports for tests using nose - what is best practice for imports of modules above current package
我最后一次尝试是用 Cookiecutter 启动一个项目,这样一开始一切都会正确设置。但是,我仍然得到 ModuleNotFoundError
。
我不要的
我不想修改 sys.path
正如许多答案似乎暗示的那样。对于这种常见问题,必须有更清洁的方法。
我做错了什么?
编辑一些额外的信息(参见来自@Nicholas 的问题):
__init__.py
的内容是
# -*- coding: utf-8 -*-
"""Top-level package for project_name."""
__author__ = """my_name"""
__email__ = 'my_email'
__version__ = '0.1.0'
由 Cookiecutter 模板生成。
在 test_module1
中,我在 ModuleNotFoundError
发生之前添加了以下内容:
import sys
import os
print(sys.path)
print(os.getcwd())
sys.path
打印一个列表,其中第一个元素是 tests
目录。
['c:\Users\...\project_name\tests',
'C:\Users\...\Miniconda3\python37.zip',
'C:\Users\...\Miniconda3\DLLs', 'C:\Users\...\Miniconda3\lib',
'C:\Users\...\Miniconda3',
'C:\Users\...\Miniconda3\lib\site- packages',
'C:\Users\...\Miniconda3\lib\site-packages\win32',
'C:\Users\...\Miniconda3\lib\site-packages\win32\lib',
'C:\Users\...\Miniconda3\lib\site-packages\Pythonwin']
我不知道第一个元素中的小写 'c' 是否重要。
os.getcwd()
打印根目录 'c:\Users\....\project_name'
。还有一个小写的'c'。
您应该创建一个虚拟环境并安装项目,以便测试模块正确解析导入语句。
在项目根目录,即包含子目录project_name
和子目录tests
的目录project_name
,创建一个setup.py
(或pyproject.toml
) 包元数据文件。有关该部分的详细信息,请参阅 here。
从现在包含安装程序 (setup.py
) 的同一项目根目录,创建并激活一个 venv 并安装您的项目:
python3 -m venv .venv
source .venv/bin/activatate # linux/macOS
# .\Scripts\activate.bat # windows
pip install --editable .
pip install pytest
pytest
如果出于某种原因你不想为你的项目创建安装程序,你可以 运行 像这样从项目目录中进行 pytest:
python3 -m pytest
与裸 pytest
命令不同,这会将当前工作目录添加到 sys.path
允许在测试中解析导入语句。