在Python单元测试中访问资源文件&主要代码

时间:2011-07-08 19:40:49

标签: python unit-testing resources

我有一个具有以下目录结构的Python项目:

project/
project/src/
project/src/somecode.py
project/src/mypackage/mymodule.py
project/src/resources/
project/src/resources/datafile1.txt

在mymodule.py中,我有一个类(我们称之为“MyClass”),需要加载datafile1.txt。当我这样做时,这种方式有效:

open(“../ resources / datafile1.txt”)

假设创建MyClass实例的代码是从somecode.py。

运行的

但问题是我对mymodule.py进行了单元测试,这些测试是在该文件中定义的,如果我保留上面描述的相对路径名,则单元测试代码会爆炸,因为现在代码是从project / src运行的/ mypackage而不是project / src,相对文件路径无法正确解析。

有关最佳实践类型方法的任何建议可以解决此问题吗?如果我将我的测试用例移动到project / src,它会使主要源文件夹与测试用例混乱。

4 个答案:

答案 0 :(得分:7)

我通常使用它从模块中获取相对路径。从未尝试过单位测试。

import os

print(os.path.join(os.path.dirname(__file__), 
                   '..',
                   'resources' 
                   'datafile1.txt'))

注意:..技巧很有效,但是如果你改变你的目录结构,你需要更新那个部分。

答案 1 :(得分:3)

除了上述答案外,我想添加一些Python 3技巧来使您的测试更加简洁。

借助pathlib库,您可以在测试中显式导入资源。它甚至处理Unix(/)和Windows()之间的分隔符差异。

假设我们有一个这样的文件夹结构:

`-- tests
    |-- test_1.py <-- You are here !
    |-- test_2.py
    `-- images
        |-- fernando1.jpg <-- You want to import this image !
        `-- fernando2.jpg

您位于test_1.py文件中,并且想要导入fernando1.jpg。在pathlib库的帮助下,您可以使用面向对象的逻辑来读取测试资源,如下所示:

from pathlib import Path

current_path = Path(os.path.dirname(os.path.realpath(__file__)))
image_path = current_path / "images" / "fernando1.jpg"

with image_path.open(mode='rb') as image :
    # do what you want with your image object

但是实际上有一些便捷的方法可以使您的代码比mode='rb'更明确,例如:

image_path.read_bytes() # Which reads bytes of an object

text_file_path.read_text() # Which returns you text file content as a string

然后去!

答案 2 :(得分:2)

在包含Python脚本的每个目录中,放置一个知道层次结构根路径的Python模块。它可以使用相对路径定义单个全局变量。在每个脚本中导入此模块。 Python首先搜索当前目录,因此它将始终使用当前目录中模块的版本,该版本将具有指向当前目录根目录的相对路径。然后使用它来查找其他文件。例如:

# rootpath.py
rootpath = "../../../"

# in your scripts
from rootpath import rootpath
datapath = os.path.join(rootpath, "src/resources/datafile1.txt")

如果您不想在每个目录中添加其他模块,可以使用以下方法:

将一个sentinel文件放在目录结构的顶层,例如thisisthetop.txt。让Python脚本向上移动目录层次结构,直到找到此文件。写下相对于该目录的所有路径名。

可能您在项目目录中已有的某个文件可用于此目的(例如,在找到src目录之前继续向上移动),或者您可以以这样的方式命名项目目录显而易见。

答案 3 :(得分:0)

文件路径将相对于您最初调用的脚本。我建议您将相对路径作为参数传递给MyClass。这样,您可以使用不同的路径,具体取决于调用MyClass的脚本。