`py.test` 和 `__init__.py` 文件
我原以为 py.test
是“独立”的,意思是它会把 test_*.py
文件“原封不动”地处理,只会导入这些文件里指定的模块,而不管周围的其他文件。结果我发现我错了。下面是我和 py.test
的对话:
$ ls
__init__.py test_pytest.py
$ cat __init__.py
$ cat test_pytest.py
def test_pytest():
assert True
$ py.test test_pytest.py
========================================================= test session starts ==========================================================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 0 items / 1 errors
================================================================ ERRORS ================================================================
___________________________________________________ ERROR collecting test_pytest.py ____________________________________________________
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/py-1.4.5-py2.7.egg/py/_path/local.py:529: in pyimport
> mod = __import__(modname, None, None, ['__doc__'])
E ImportError: No module named test_pytest
======================================================= 1 error in 0.01 seconds ========================================================
$ rm __init__.py
$ py.test test_pytest.py
========================================================= test session starts ==========================================================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items
test_pytest.py .
======================================================= 1 passed in 0.01 seconds =======================================================
$
我该怎么做才能让 py.test
正常工作,同时又保留我的 __init__.py
文件呢?
更新
在评论中,Holger Krekel 问我父目录的名字是什么。结果我发现,只有在父目录的名字是特定的情况下(比如和某个已安装的包同名,如 distutils
),我才能重现上面的错误。请看这里:
~/test_min
$ tree
.
└── distutils
├── __init__.py
└── test_pytest.py
1 directory, 2 files
~/test_min
$ cat distutils/__init__.py
~/test_min
$ cat distutils/test_pytest.py
def test_pytest():
assert True
~/test_min
$ py.test distutils/test_pytest.py
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 0 items / 1 errors
=============================== ERRORS ===============================
_____________ ERROR collecting distutils/test_pytest.py ______________
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/py-1.4.5-py2.7.egg/py/_path/local.py:529: in pyimport
> mod = __import__(modname, None, None, ['__doc__'])
E ImportError: No module named test_pytest
====================== 1 error in 0.01 seconds =======================
~/test_min
$ rm distutils/__init__.py
~/test_min
$ py.test distutils/test_pytest.py
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items
distutils/test_pytest.py .
====================== 1 passed in 0.01 seconds ======================
~/test_min
$ touch __init__.py
~/test_min
$ ls
__init__.py distutils
~/test_min
$ touch distutils/__init__.py
~/test_min
$ py.test distutils/test_pytest.py
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items
distutils/test_pytest.py .
====================== 1 passed in 0.02 seconds ======================
~/test_min
$ rm __init__.py
~/test_min
$ py.test distutils/test_pytest.py
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 0 items / 1 errors
=============================== ERRORS ===============================
_____________ ERROR collecting distutils/test_pytest.py ______________
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/py-1.4.5-py2.7.egg/py/_path/local.py:529: in pyimport
> mod = __import__(modname, None, None, ['__doc__'])
E ImportError: No module named test_pytest
====================== 1 error in 0.01 seconds =======================
~/test_min
$ mv distutils foobar
~/test_min
$ py.test foobar/test_pytest.py
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items
foobar/test_pytest.py .
====================== 1 passed in 0.01 seconds ======================
~/test_min
$
希望这些额外的信息能有所帮助。
3 个回答
你可以告诉pytest忽略特定的文件或文件模式,具体的做法可以在这里找到。你只需要在项目的根目录下放一个conftest.py
文件,里面列出你希望pytest
忽略的文件:
不过,很多项目会有一个setup.py文件,而你可能不想让它被导入。此外,有些文件可能只能被特定版本的Python导入。对于这种情况,你可以通过在conftest.py文件中动态定义要忽略的文件来解决:
# content of conftest.py import sys collect_ignore = ["setup.py"]
我真的建议你把这个文件夹改个名字,不要叫“distutils”。为什么呢?因为你这样会覆盖掉一个已经存在的模块。当你的代码里出现“import distutils”或者“from distutils import *”时,它会优先使用你这个文件夹里的内容,而不是系统自带的那个模块。
如果distutils模块已经被加载过了,你的distutils就不会被加载,因为全局环境里已经有这个名字了。
其实,把这个文件夹改个名字(比如叫tests)要简单得多,而不是去和py.test或者Python内部的机制对着干。
看起来 py.test 在用 py._path.pyimport
来打开你的文件。如果这个文件夹里有一个 __init__.py
文件,它就会把你的文件当成一个模块来处理;如果没有这个文件,它就直接打开文件。简单来说,要么删掉 __init__.py
,要么把你的测试放到项目代码之外的其他文件夹里(<--- 这是个好主意)。
https://py.readthedocs.io/en/latest/path.html#py._path.local.LocalPath.pyimport