【发布时间】:2019-03-04 20:55:23
【问题描述】:
这是我的项目布局:
project
+-- package_1
| +-- __init__.py
| +-- module_1.py tests
+-- package_2
| +-- __init__.py
| +-- module_2.py tests
+-- tests
+-- package_1
| +-- __init__.py
| +-- test_module_1.py
+-- package_2
+-- __init__.py
+-- test_module_2.py
test_module_1.py 开始于:
import package_1.module_1
test_module_2.py 开始于:
import package_2.module_2
从项目目录运行python -m unittest discover tests 会报错:
EE
======================================================================
ERROR: package_1.test_module_1 (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: package_1.test_module_1
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 434, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 375, in _get_module_from_name
__import__(name)
File "/Users/maggyero/project/tests/package_1/test_module_1.py", line 1, in <module>
import package_1.module_1
ModuleNotFoundError: No module named 'package_1.module_1'
======================================================================
ERROR: package_2.test_module_2 (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: package_2.test_module_2
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 434, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 375, in _get_module_from_name
__import__(name)
File "/Users/maggyero/project/tests/package_2/test_module_2.py", line 1, in <module>
import package_2.module_2
ModuleNotFoundError: No module named 'package_2.module_2'
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (errors=2)
在test_module_1.py开头添加import sys; print(sys.modules['package_1'])和在test_module_2.py开头添加import sys; print(sys.modules['package_2']),看看sys.modules里面有什么cache表示tests目录下的package_1和package_2已经导入在测试发现期间:
<module 'package_1' from '/Users/maggyero/project/tests/package_1/__init__.py'>
<module 'package_2' from '/Users/maggyero/project/tests/package_2/__init__.py'>
导入以前导入的包会重用来自sys.modules 的相同缓存包,即使sys.path 已经更新。因此,当执行import package_1.module_1 和import package_2.module_2 时,首先重新导入测试目录(包含test_module_1 和test_module_2)中的package_1 和package_2,而不是项目目录(包含module_1 和module_2)中的package_1 和package_2,然后重新导入module_1 和module_2被导入,引发ModuleNotFoundError。
除了重命名之外,是否有避免测试目录中的包影响项目目录的包的解决方法?
更新(发布答案)
以下 Laurent Laporte 的替代解决方案(他避免在执行 sys.modules 时已经在 sys.modules 中使用 import package_1.module_1 和 import package_2.module_2,而是使用 'tests.package_1' 和 'tests.package_2',这要归功于顶级目录的变化)是更新sys.path并重新加载test_module_1.py中的包:
import importlib
import pathlib
import sys
sys.path.insert(0, pathlib.Path(__file__).resolve().parents[2])
import package_1
importlib.reload(package_1)
import package_1.module_1
和 test_module_2.py:
import importlib
import pathlib
import sys
sys.path.insert(0, pathlib.Path(__file__).resolve().parents[2])
import package_2
importlib.reload(package_2)
import package_2.module_2
此解决方案的唯一优点是测试目录不需要是常规包(即具有 __init__.py 文件)。因此,当 Unittest 允许递归命名空间包发现时不会有任何优势(目前票证仍处于打开状态:https://bugs.python.org/issue23882)。
应该首选Laurent Laporte 的解决方案,因为包限定 比包重新加载 更能区分同名包。另一个好的解决方案是包重命名(例如,将包_1 和包_2 从测试目录重命名为 test_package_1 和 test_package_2)。
【问题讨论】:
-
将
package1重命名为test_package1。
标签: python unit-testing import python-import python-unittest