Skip to content Skip to sidebar Skip to footer

Change Pytest Working Directory To Test Case Directory

I have the following pytest directory structure: system_tests/ ├── conftest ├── pytest.ini │ ├── suite_1/ │ └── test_A.py │ └─

Solution 1:

The following function-level fixture will change to the test case directory, run the test (yield), then change back to the calling directory to avoid side-effects, as suggested by @hi2meuk:

@pytest.fixturedefchange_test_dir(request):
    os.chdir(request.fspath.dirname)
    yield
    os.chdir(request.config.invocation_dir)
  • request is a built-in pytest fixture
  • fspath is the LocalPath to the test module being executed
  • dirname is the directory of the test module
  • request.config.invocationdir - the folder from which pytest was executed
  • request.config.rootdir - pytest root, doesn't change based on where you run pytest. Not used here, but could be useful.

Any processes that are kicked off by the test will use the test case folder as their working directory and copy their logs, outputs, etc. there, regardless of where the test suite was executed.

EDIT: Improved Solution

Using 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 to change the cwd for all tests:

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

Solution 2:

Many options open to you to achieve this. Here are a few.

1. Write a pytest fixture to check if the current working directory is equal to the desired working directory, and if not, then move all the artifact files to the desired directory. If the artifacts you are generating are all the same type of file (e.g. *.jpg, *.png, *.gif) and you just want them to be in a different directory, then this may suffice. Something like this could work

from pathlib import Path
import shutil

@pytest.fixturedefcleanup_artifacts():
    yieldNone
    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)

And then you can add this fixture to your tests as needed.

2. You can configure the pytest rootdir to be the desired directory, since pytest uses the rootdir to store project/testrun specific info.

When you run pytest, run it as

pytest --rootdir=desired_path

See here for more info: https://docs.pytest.org/en/latest/customize.html#initialization-determining-rootdir-and-inifile

If both don't work for you, tell more about what your requirements are. Surely this can be done with pytest.

Solution 3:

A different and, IMHO more robust approach: always reference your files by the complete path.

__file__ is an automatically declared Python variable that is the name of the current module. So in your test_B.py file, it would have the value: system_tests/suite_2/sub_suite_2a/test_B.py. Just get the parent and choose where to write your files.

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

Now you have all of them in the same place and can tell your version control system to ignore them.

If the code is inside a library, better use an absolute path:

import os
from pathlib importPathtest_data_dir= Path(__file__).parent.absolute() / "test_data"

Solution 4:

Instead of creating a fixture for each directory like suggested by @DV82XL you can simply use monkeypatch to achieve the same:

import pytest
from pathlib import Path

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



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

Post a Comment for "Change Pytest Working Directory To Test Case Directory"