将 pytest 工作目录更改为测试用例目录

Change pytest working directory to test case directory

我有以下pytest目录结构:

system_tests/
  ├── conftest
  ├── pytest.ini
  │
  ├── suite_1/
  │    └── test_A.py
  │   
  └── suite_2/
       └── sub_suite_2a/
            └── test_B.py

当每个测试方法 运行s 时,多个第三方 libraries/processes 在当前工作目录中生成工件。

有没有一种简单的方法可以强制 pytest 始终使用测试 class 文件夹作为工作目录,这样无论 如何 哪里我运行一个测试从?

您可以选择多种方式来实现这一目标。这里有几个。

1。 编写一个 pytest fixture 来检查当前工作目录是否等于所需的工作目录,如果不相等,则将所有工件文件移动到所需目录。 如果您生成的工件都​​是同一类型的文件(例如 *.jpg、*.png、*.gif)并且您只是希望它们位于不同的目录中,那么这可能就足够了。 这样的东西可以工作

from pathlib import Path
import shutil

@pytest.fixture
def cleanup_artifacts():
    yield None
    cwd = Path.cwd()
    desired_dir = Path.home() / 'system-tests' / 'suite-2' / 'sub_suite_2a'
    if cwd != desired_dir:
        for f in cwd.glob('*.jpg'):
            shutil.move(f, desired_dir)

然后您可以根据需要将此固定装置添加到您的测试中。

2。 您可以将 pytest rootdir 配置为所需的目录,因为 pytest 使用 rootdir 来存储 project/testrun 特定信息。

当你 运行 pytest 时,运行 它作为

pytest --rootdir=desired_path

查看此处了解更多信息:https://docs.pytest.org/en/latest/customize.html#initialization-determining-rootdir-and-inifile

如果两者都不适合您,请详细说明您的要求。当然这可以用 pytest 来完成。

下面的函数级 fixture 将更改为测试用例目录,运行 测试(yield),然后更改回调用目录以避免副作用,正如@hi2meuk 所建议的:

@pytest.fixture
def change_test_dir(request):
    os.chdir(request.fspath.dirname)
    yield
    os.chdir(request.config.invocation_dir)
  • request 是内置的 pytest fixture
  • fspathLocalPath到正在执行的测试模块
  • dirname是测试模块的目录
  • request.config.invocationdir - 执行 pytest 的文件夹
  • request.config.rootdir - pytest root,不会根据您 运行 pytest 的位置而改变。此处未使用,但可能会有用。

任何由测试启动的进程都将使用测试用例文件夹作为它们的工作目录,并将它们的日志、输出等复制到那里,而不管测试套件在哪里执行。

编辑:改进的解决方案

使用monkeypatch as suggested by @Kound removes the boilerplate code to restore the cwd. You can also enable autouse to automatically apply this fixture to all test functions. Add the following fixture to conftest.py更改所有测试的cwd:

@pytest.fixture(autouse=True)
def change_test_dir(request, monkeypatch):
    monkeypatch.chdir(request.fspath.dirname)

一种不同的,恕我直言,更强大的方法:始终通过完整路径引用您的文件。

__file__ 是一个自动声明的 Python 变量,它是当前模块的名称。因此,在您的 test_B.py 文件中,它的值为:system_tests/suite_2/sub_suite_2a/test_B.py。只需获取父项并选择写入文件的位置。

from pathlib import Path
test_data_dir = Path(__file__).parent / "test_data"

现在您将所有这些都放在同一个地方,并且可以告诉您的版本控制系统忽略它们。

如果代码在库中,最好使用绝对路径:

import os
from pathlib import Path

test_data_dir = Path(__file__).parent.absolute() / "test_data"

无需像@DV82XL 建议的那样为每个目录创建固定装置,您可以简单地使用 monkeypatch 来实现相同的目的:

import pytest
from pathlib import Path

@pytest.fixture
def base_path() -> Path:
    """Get the current folder of the test"""
    return Path(__file__).parent



def test_something(base_path: Path, monkeypatch: pytest.MonkeyPatch):
    monkeypatch.chdir(base_path / "data" )
    # Do something in the data folder