为什么我的当前目录没有显示在 Windows 上使用 pytest 的路径中?



i具有以下文件夹结构;

myapp
  myapp
     __init__.py
  tests
     test_myapp.py

我的PWD是

C:Userswwernerprogrammingmyapp

我有以下测试设置:

import sys
import pprint
def test_cool():
    pprint.pprint(sys.path)
    assert False

产生以下路径:

['C:\Users\wwerner\programming\myapp\tests',
 'C:\Users\wwerner\programming\envs\myapp\Scripts',
 'C:\Windows\system32\python34.zip',
 'C:\Python34\DLLs',
 'C:\Python34\lib',
 'C:\Python34',
 'C:\Users\wwerner\programming\envs\myapp',
 'C:\Users\wwerner\programming\envs\myapp\lib\site-packages']

,当我尝试使用import myapp时,我会收到以下错误:

ImportError: No module named 'myapp'

,看起来它没有将当前目录添加到我的路径中。

通过更改我的导入行以看起来这样:

import sys
sys.path.insert(0, '.')
import myapp

我可以毫无问题地导入myapp

为什么我的当前目录在运行pytest时不会出现在路径中?我唯一的解决方法是将.插入sys.path?(如果很重要,我正在使用Python 3.4)

啊!

比较了我的CookieCutter回购的布局后,事实证明它比这更简单(和更好)。

tests/
    __init__.py
    test_myapp.py

简单地将__init__.py文件添加到我的测试dir中,我可以从我的主目录运行py.test

使用可安装软件包

如果您有一个可安装的软件包(已定义的构建系统定义的setup.pypyproject.toml文件),则最好针对安装的代码进行测试。在VENV中安装代码将使导入语句正确解决该VENV。

pip install --editable .
pytest

将问题中显示为可安装软件包中显示的项目的最简单方法是添加此setup.py

from setuptools import setup
setup(
    name="myapp",
    version="0.1",
    packages=["myapp"],
)

这将把myapp代码放在虚拟环境的sys.path中的/path/to/myapp/.venv/lib/python3.XY/site-packages上。现在可以从site-packages DIR导入myapp,就像用户安装一样。在测试执行过程中,当前的工作目录既不需要也不希望在sys.path上存在。

不使用可安装的软件包

问题中显示的项目没有任何安装程序,因此无法安装。它仍然可以通过确保项目root(即包含myapptests作为子目录的目录)进行测试。

最好的方法是使用python -m pytest,而不是调用Bare pytest命令。当您使用python -m pytest时,它将当前的工作目录添加到sys.path的开始。当执行包裹为__main__(在此处记录)时,这是正常的Python行为,并且也是Pytest的记录用法 - 请参见调用pytestpython -m pytest

调用CC_24

为什么将__init__.py添加到tests子目录(不工作)?

问题中显示的目录结构是" 测试"应用程序代码'图案,在这里记录。这也是我建议的目录结构,因为它在库/应用程序代码和测试代码之间创建了一个明确的区别。

使用" 测试"应用程序代码&quot时,不建议在测试目录中添加__init__.py文件。结构,由于测试文件并非打算"打包"(例如,测试文件实际上不需要从其他测试文件中导入,并且无需安装包装的最终用户)。

添加myapp/__init__.py的原因实际上允许myapppytest导入(如Wayne的答案所示)实际上是事故,因为在测试收集阶段测试发现附加sys.path的方式。这被描述为"有问题"在文档中

...这引入了一个微妙的问题:为了加载来自tests目录的测试模块,PyTest将存储库的根本置于sys.path,这增加了mypkg现在也可以导入的副作用,该副作用也可以导入

,如果您打算在测试目录中包含__init__.py文件,以避免导入系统的这种混乱。

但是,不依赖这种副作用的最佳理由也许是Pytest Collection实际上可以在多种模式下使用(请参阅导入模式),而Wayne的答案依赖于使用" Prepend"的Pytest。导入模式。预端模式当前是默认值,但文档提到的是将来版本将切换为使用" Ementlib"。默认模式:

我们打算使importlib未来版本中的默认值。

所接受的答案不适用于pytest --import-mode=importlib,因此在某个阶段将完全停止工作。

sys.path自动包含脚本的目录,而不是当前的工作目录。

我猜想您的脚本放在tests目录中。基于此假设,您的代码应该看起来像这样:

import sys
import os
ROOT_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(ROOT_DIR)
import myapp # Should work now

使用环境变量PYTHONPATH

Windows:

set PYTHONPATH=.
py.test

in unix:

PYTHONPATH=. py.test

最新更新