pytest导入自定义模块报错
问题描述
Terminal
中通过pytest
执行用例会返回异常:ModuleNotFoundError: No module named '***'
通过python -m pytest
执行用例可以正常执行
通过pycharm
进行执行对应的用例文件,可以正常执行
目录结构及test_login.py
的文件内容如下:
问题原因
默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys
模块的path
变量中,如果找不到模块所在的路径就会报错,所以自定义模块要处于 sys.path
里才能被导入。
上图中第一项是''
,使用OS模块查看
发现第一项是当前文件的目录,所以V3.utils
即不在test_login.py
当前目录下,也不在所有已安装的内置模块和第三方模块,肯定找不到,那为什么通过python -m pytest
执行和通过pycharm
进行执行,可以正常执行呢?
python -m pytes
t会把当前项目的目录添加到sys.path
(指定模块的搜索路径)中,通过pycharm
进行运行的时候也会把项目当前所在路径添加到sys.path中
问题解决
网上大部分的解决办法都是手动添加到sys.path中
方法一
直接修改sys.path
,添加要搜索的目录:
>>> import sys
>>> sys.path.append('文件路径')
这种方法是在运行时修改,运行结束后失效。
方法二
在test_login.py
中将目录直接加进去就行
path = os.path.abspath(os.path.dirname(os.path.dirname(__f11e__)))
sys.path.insert(0,path)
方法三
由于手动添加总觉得有些麻烦,不想手动添加也可以进行导入,所以只需要在根目录下新建一个conftest.py
文件或者scripts
下新建一个__init__.py
文件即可
为了解答此疑惑,了解了一下pytest导入模块的机制,以以下目录进行说明
例如:
root/
|- foo/
|- __init__.py
|- conftest.py
|- bar/
|- __init__.py
|- tests/
|- __init__.py
|- test_foo.py
执行pytest root/
后,Pytest首先会找到 foo/bar/tests/test_foo.py
,因为同一文件夹中存在__init__.py
,所以foo/bar/tests/
会被识别成package,然后它会向上搜索,直到找到仍包含 __init__.py
的最后一个文件夹 ,此处是foo/
,所以他会将root/
到插入到 sys.path
,这样就可以使test_foo.py
作为模块 foo.bar.tests.test_foo
导入
相同的逻辑也适用于该conftest.py
文件:它将作为foo.conftest
模块导入。
root/
|- foo/
|- conftest.py
|- bar/
|- tests/
|- test_foo.py
执行pytest root/
后,Pytest首先会找到 foo/bar/tests/test_foo.py
,因为同一文件夹中不存在__init__.py
,所以不会被识别成package,会把用例视为一个独立的模块。然后为了导入 test_foo.py
它会添加 root/foo/bar/tests
到 sys.path
,同样,conftest.py
也被视为独立的模块,通过添加其所在目录root/foo
到sys.path
中,将其以模块形式导入。