让pytest查找测试脚本所在的基础目录

4
在pytest中,我的测试脚本会将计算结果与通过加载的基准结果进行比较。
SCRIPTLOC = os.path.dirname(__file__)
TESTBASELINE = os.path.join(SCRIPTLOC, 'baseline', 'baseline.csv')
baseline = pandas.DataFrame.from_csv(TESTBASELINE)

是否有一种非模板化的方法来告诉pytest从脚本的根目录开始查找,而不是通过SCRIPTLOC获取绝对位置?

这与pytest完全无关,完全是你自己的代码,因此完全由你负责。 - user78110
也许我表达不太准确。在pytest中,如何引用相对于测试脚本的目录?我放置了代码以展示我一直在尝试解决这个问题。 - Richard Foo
1
目前还没有,这是 Python 的标准问题 - 诸如 pkgutil/pkg_resources 这样的东西可以提供帮助。 - user78110
1个回答

14
如果你只是想找到pytest中使用__file__的等效方法,你可以在测试中添加request fixture,并使用request.path
来自docs的内容:
class FixtureRequest
  ...
  property path: Path
      Path where the test function was collected.
所以一个例子可能是这样的:
def test_script_loc(request):
    baseline = request.path.parent.joinpath('baseline', 'baseline.cvs')
    print(baseline)

如果你想要避免模板代码,那么这样做对你来说并没有太多好处(假设我理解你所说的“非模板代码”是什么意思)。
就个人而言,我认为使用fixture更加明确(在pytest的习语中),但我更喜欢在另一个fixture中封装请求操作,这样我只需查看测试方法的方法签名,就能明确地知道我正在获取样本测试数据。
这是我使用的一小段代码(根据您的问题进行了修改,我使用了子目录层次结构):
# in conftest.py
import pytest

from pathlib import Path


@pytest.fixture(scope="module")
def script_loc(request):
    '''Return the directory of the currently running test script'''

    return request.path.parent

和示例用法

def test_script_loc(script_loc):
    baseline = script_loc.joinpath('baseline/baseline.cvs')
    print(baseline)

pytest <= 6 兼容性

我早就停止支持旧版的Python,而是使用pathlib
因此,我不再返回LocalPath对象,也不依赖它们的API,但偶尔我仍然需要支持使用pytest<=6.0的平台,这些平台尚未具备{{link1:request.path属性}}。
pytest团队还计划最终弃用py.path,并将其内部转移到标准库的pathlib中{{link2:链接2}}。这一过程早在pytest 3.9.0中开始,引入了tmp_path,但实际上删除LocalPath属性可能需要一些时间。

在您可以升级到pytest>=7.0之前,将LocalPath转换为Path非常容易。

以下是使用Path对象的上述示例的变体,根据您的需要进行调整:

# in conftest.py
import pytest

from pathlib import Path


@pytest.fixture(scope="module")
def script_loc(request):
    '''Return the directory of the currently running test script'''

    return Path(request.fspath).parent 

和示例用法

def test_script_loc(script_loc):
    baseline = script_loc.joinpath('baseline/baseline.cvs')
    print(baseline)

遗留的py.path

对于依赖于py.path和/或需要Python 2.x支持的旧版本pytest,此答案的原始版本使用request.fspath属性返回py.path.LocalPath的实例。

来自文档

class FixtureRequest
  ...
  fspath
      the file system path of the test module which collected this test.
所以一个例子可能是这样的:
def test_script_loc(request):
    baseline = os.path.join(request.fspath.dirname, 'baseline', 'baseline.cvs')
    print(baseline)

灯具的变种可能如下所示:
# in conftest.py
import pytest

@pytest.fixture(scope="module")
def script_loc(request):
    '''Return the directory of the currently running test script'''

    # uses .join instead of .dirname so we get a LocalPath object instead of
    # a string. LocalPath.join calls normpath for us when joining the path
    return request.fspath.join('..') 

以及示例用法:

def test_script_loc(script_loc):
    baseline = script_loc.join('baseline/baseline.cvs')
    print(baseline)

你发布的第二个示例似乎不起作用,我得到了这个错误:直接调用了"get_test_workbook"夹具。夹具不应该直接被调用。 - undefined
@RaleighL. 如果你们在测试函数的签名中忘记将fixture作为参数添加,并且在函数体中直接调用fixture,那么这个错误应该只会发生。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接