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

DV8*_*2XL 3 python working-directory pytest

我有以下 pytest 目录结构:

system_tests/
  ??? conftest
  ??? pytest.ini
  ?
  ??? suite_1/
  ?   ??? test_A.py
  ?   
  ??? suite_2/
      ??? sub_suite_2a/
      ?   ??? test_B.py
      ??? sub_suite_2b/
          ??? test_C.py
Run Code Online (Sandbox Code Playgroud)

当每个测试方法运行时,许多第三方库/进程会在当前工作目录中生成工件。当我从sub_suite文件夹中运行 pytest 时(使用 CLI 或 IDE 的“播放”按钮),文件会sub_suite在我想要的文件夹中生成。但是,当我从system_tests文件夹运行 pytest以运行所有测试时,所有工件都在system_tests文件夹中创建,这不是我想要的。

有没有一种简单的方法可以强制 pytest 始终使用测试类文件夹作为工作目录,这样无论我如何或从哪里运行测试我都会得到相同的结果?

Kou*_*und 8

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

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


DV8*_*2XL 7

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

@pytest.fixture(scope="function")
def change_test_dir(request):
    os.chdir(request.fspath.dirname)
    yield
    os.chdir(request.config.invocation_dir)
Run Code Online (Sandbox Code Playgroud)
  • request 是一个内置的 pytest 夹具
  • fspathLocalPath正在执行的测试模块
  • dirname 是测试模块的目录
  • request.config.invocationdir - 从中执行 pytest 的文件夹
  • request.config.rootdir- pytest 根,不会根据您运行 pytest 的位置而改变。此处未使用,但可能有用。

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

  • 提议的固定装置引入了副作用,会干扰其他测试,可能在将来会让你感到困惑。在按照@Farhan Kathawala 的答案返回之前,使用yield 然后cwd 返回到`request.config.inspiration_dir`。 (3认同)

nev*_*ves 6

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

__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"
Run Code Online (Sandbox Code Playgroud)

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

如果代码位于库内,最好使用绝对路径,因为您不知道它将安装在哪里:

import os
from pathlib import Path

test_data_dir = Path(__file__).parent.absolute() / "test_data"
Run Code Online (Sandbox Code Playgroud)