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

Ada*_*kin 7 python resources unit-testing

我有一个具有以下目录结构的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.当我这样做时,这种方式有效:

打开("../resources/datafile1.txt")

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

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

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

小智 8

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

import os

print(os.path.join(os.path.dirname(__file__), 
                   '..',
                   'resources' 
                   'datafile1.txt'))
Run Code Online (Sandbox Code Playgroud)

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


Bac*_*hrc 6

除了上述答案之外,我想添加一些 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
Run Code Online (Sandbox Code Playgroud)

您在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
Run Code Online (Sandbox Code Playgroud)

但是实际上有一些方便的方法可以使您的代码比 更明确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
Run Code Online (Sandbox Code Playgroud)

你去吧!


kin*_*all 5

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

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

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

如果你不想在每个目录中放置额外的模块,你可以使用这种方法:

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

可能您在项目目录中已有的某些文件可用于此目的(例如,继续向上移动直到找到一个src目录),或者您可以以这样的方式命名项目目录以使其明显。