使用nose进行测试的Python导入 - 处理当前包以上模块导入的最佳实践是什么

66 投票
3 回答
22464 浏览
提问于 2025-04-16 21:22

这个问题经常以不同的形式被提出来,通常会得到一些“哈哈,你没搞明白”的回答。我觉得这是因为大家(包括我自己)在尝试用一种常识性的场景来实现,但解决方案并不明显(如果你之前没做过的话)。

我希望能得到一个“让问题迎刃而解”的答案。

给定

project/
    __init__.py
    /code
        __init__.py
        sut.py
    /tests
        __init__.py
        test_sut.py

测试文件 tests_sut.py 开始的地方:

import code.sut

在根目录下运行 nosetests 会得到:

ImportError: No module named code.sut

尝试过的方法:

a) 使用相对路径

from ..code import sut

b) 将项目的根目录添加到 PYTHONPATH

c) 在每个测试模块开始时,使用

sys.path.append

在导入之前添加 .. 路径。

d) 记得在运行测试之前,

setup.py 

对项目进行一次安装,把模块放到 site-packages 里。


所以要求是测试文件要放在测试包的根目录下,并且能够访问到项目。以上每种方法对我来说都感觉不“自然”,而且有些方法还挺麻烦的!

在 Java 中,这个问题很好解决,因为你的构建工具或 IDE 会把所有的类放到类路径上。也许问题在于我对 Python 期待了“魔法”?我注意到在 Flask 这个网页框架的测试中,选项 d) 似乎是更受欢迎的选择。

无论如何,下面的建议如果能推荐一个更好的解决方案,就能消除我心中的“奇怪感”。

3 个回答

5

我知道已经有一个答案被认可了,但我觉得分享其他选择也是很有意义的 :)

有一个叫做 nose-pathmunge 的工具,它可以让你在运行 nosestests 时,控制 sys.path 的设置。

46

我也遇到过同样的问题,后来在一个相关的问题中找到了一条答案,对我有帮助。

只需要把项目根目录下的 __init__.py 文件删除就可以了。

12

你已经很好地回答了自己的问题。
D(安装到系统位置)是分发代码时的首选。我通常使用C(修改sys.path),因为我不想在系统范围内安装我数百个自定义库。从理论上讲,A(相对导入)似乎更好,但在某些情况下会失败。
B(PYTHONPATH)在我看来真的不合适,主要是用于测试。

这基本上总结了所有的选项。你喜欢的选项(Python神奇地知道去哪里找)其实并不是一个可行的解决方案,因为它可能导致不可预测的结果,比如自动找到与项目无关的库。

在我看来,最好的做法是在你的程序的入口点放置以下内容:

import sys, os
sys.path = [os.path.abspath(os.path.dirname(__file__))] + sys.path

撰写回答