6. pytest -- temporary directory and file

Posted by laurajohn89 on Thu, 24 Oct 2019 11:14:21 +0200

Catalog

1. Relevant fixture s

1.1. tmp_path

TMP path is a use case level fixture that returns a unique temporary directory object (pathlib.Path).

Let's look at the following example:

# src/chapter-6/test_tmp_path.py

CONTENT = "content"


def test_create_file(tmp_path):
    d = tmp_path / "sub"  
    d.mkdir()  # Create a subdirectory
    p = d / "hello.txt"
    p.write_text(CONTENT)
    assert p.read_text() == CONTENT
    assert len(list(tmp_path.iterdir())) == 1  # iterdir() iterates the directory and returns the iterator
    assert 0  # To show, force to fail

Implementation:

λ pipenv run pytest -q -s src/chapter-6/test_tmp_path.py
F
==================================== FAILURES =====================================
________________________________ test_create_file _________________________________

tmp_path = WindowsPath('C:/Users/luyao/AppData/Local/Temp/pytest-of-luyao/pytest-4/test_create_file0')

    def test_create_file(tmp_path):
        d = tmp_path / "sub"
        d.mkdir()  # Create a subdirectory
        p = d / "hello.txt"
        p.write_text(CONTENT)
        assert p.read_text() == CONTENT
        assert len(list(tmp_path.iterdir())) == 1  # iterdir() iterates the directory and returns the iterator
>       assert 0  # To show, force to fail
E       assert 0

src\chapter-6\test_tmp_path.py:32: AssertionError
1 failed in 0.06s

It can be seen that:

  • TMP Path returns different types of pathlib.Path objects in different operating systems. Here, under Windows system, it returns WindowsPath objects, which are subclass objects of Path.
  • The path object can use the / operator instead of the commonly used method of os.path.join(); for more information about how to use pathlib, see: https://docs.python.org/3.7/library/pathlib.html

1.2. tmp_path_factory

TMP path factory is a session level fixture, which is used to create any temporary directory in other fixtures or use cases.

Looking at the source code of TMP path fixture in the previous chapter, we can see that TMP path is an example of using TMP path factory:

# _pytest.tmpdir

@pytest.fixture
def tmp_path(request, tmp_path_factory):
    """Return a temporary directory path object
    which is unique to each test function invocation,
    created as a sub directory of the base temporary
    directory.  The returned object is a :class:`pathlib.Path`
    object.

    .. note::

        in python < 3.6 this is a pathlib2.Path
    """

    return _mk_tmp(request, tmp_path_factory)

@pytest.fixture(scope="session")
def tmp_path_factory(request):
    """Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
    """
    return request.config._tmp_path_factory

It can be seen that:

  • TMP path calls TMP path factory.
  • TMP path factory returns a pytest.tmpdir.TempPathFactory object.
  • Further check the source code of TMP:

    def _mk_tmp(request, factory):
      name = request.node.name
      name = re.sub(r"[\W]", "_", name)
      MAXVAL = 30
      name = name[:MAXVAL]
      return factory.mktemp(name, numbered=True)

    It can be seen that tmp_path finally calls TempPathFactory.mktemp(), which returns a pathlib.Path object;

1.3. tmpdir

TMP path is a use case level fixture that returns a unique temporary directory object( py.path.local ), which provides the method of os.path;

The above example It can also be modified as follows:

# src/chapter-6/test_tmpdir.py

CONTENT = "content"


def test_create_file(tmpdir):
    p = tmpdir.mkdir("sub").join("hello.txt")  # Create subfolders and create new files
    p.write(CONTENT)
    assert p.read() == CONTENT
    assert len(tmpdir.listdir()) == 1  # iterdir() iterates the directory and returns the list
    assert 0  # To show, force to fail

Implementation:

λ pipenv run pytest -q -s src/chapter-6/test_tmpdir.py
F
==================================== FAILURES =====================================
________________________________ test_create_file _________________________________
tmpdir = local('C:\\Users\\luyao\\AppData\\Local\\Temp\\pytest-of-luyao\\pytest-6\\test_create_file0')

    def test_create_file(tmpdir):
        p = tmpdir.mkdir("sub").join("hello.txt")  # Create subfolders and create new files
        p.write(CONTENT)
        assert p.read() == CONTENT
        assert len(tmpdir.listdir()) == 1  # iterdir() iterates the directory and returns the list
>       assert 0  # To show, force to fail
E       assert 0

src\chapter-6\test_tmpdir.py:30: AssertionError
1 failed in 0.06s

In fact, tmpdir also calls TMP? Path. It just encapsulates the return value with py.path.local():

# _pytest.tmpdir

@pytest.fixture
def tmpdir(tmp_path):
    """Return a temporary directory path object
    which is unique to each test function invocation,
    created as a sub directory of the base temporary
    directory.  The returned object is a `py.path.local`_
    path object.

    .. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
    """
    return py.path.local(tmp_path)

1.4. tmpdir_factory

TMPDIR factory is a session level fixture, which is used to create any temporary directory in other fixtures or use cases.

Suppose that a test session needs to use a large image file generated by the program. Compared with generating a file once for each test case, it is better to generate only once for each session:

import pytest


@pytest.fixture(scope="session")
def image_file(tmpdir_factory):
    img = compute_expensive_image()
    fn = tmpdir_factory.mktemp("data").join("img.png")
    img.save(str(fn))
    return fn


def test_histogram(image_file):
    img = load_image(image_file)
    # compute and test histogram

1.5. difference

fixture Scope of action return type
tmp_path Use case level (function) pathlib.Path
tmp_path_factory session level TempPathFactory
tmpdir Use case level (function) py.local.path
tmpdir_factory session level TempDirFactory

2. Default basic temporary directory

When creating temporary directories, the above fixture s are all created in the default temporary directory of the system (for example, the% temp% directory of Windows system); you can customize the default basic temporary directory by specifying the -- basetemp=mydir option;

λ pipenv run pytest -q -s --basetemp="/d/temp" src/chapter-6/test_tmpdir.py
F
==================================== FAILURES =====================================
________________________________ test_create_file _________________________________
tmpdir = local('D:\\temp\\test_create_file0')

    def test_create_file(tmpdir):
        p = tmpdir.mkdir("sub").join("hello.txt")  # Create subfolders and create new files
        p.write(CONTENT)
        assert p.read() == CONTENT
        assert len(tmpdir.listdir()) == 1  # iterdir() iterates the directory and returns the list
>       assert 0  # To show, force to fail
E       assert 0

src\chapter-6\test_tmpdir.py:30: AssertionError
1 failed in 0.04s

GitHub warehouse address: https://github.com/luizyao/pytest-chinese-doc

Topics: Python Session Windows github