Usage

Test Scenarios

There are several approaches to implementing tests using pyfakefs.

Patch using fake_filesystem_unittest

If you are using the Python unittest package, the easiest approach is to use test classes derived from fake_filesystem_unittest.TestCase.

If you call setUpPyfakefs() in your setUp(), pyfakefs will automatically find all real file functions and modules, and stub these out with the fake file system functions and modules:

from fake_filesystem_unittest import TestCase

class ExampleTestCase(TestCase):
    def setUp(self):
        self.setUpPyfakefs()

    def test_create_file(self):
        file_path = '/test/file.txt'
        self.assertFalse(os.path.exists(file_path))
        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

The usage is explained in more detail in Automatically find and patch file functions and modules and demonstrated in the files example.py and example_test.py.

Patch using the PyTest plugin

If you use PyTest, you will be interested in the PyTest plugin in pyfakefs. This automatically patches all file system functions and modules in a similar manner as described above.

The PyTest plugin provides the fs fixture for use in your test. For example:

def my_fakefs_test(fs):
    # "fs" is the reference to the fake file system
    fs.create_file('/var/data/xx1.txt')
    assert os.path.exists('/var/data/xx1.txt')

Patch using fake_filesystem_unittest.Patcher

If you are using other means of testing like nose, you can do the patching using fake_filesystem_unittest.Patcher - the class doing the actual work of replacing the filesystem modules with the fake modules in the first two approaches.

The easiest way is to just use Patcher as a context manager:

from fake_filesystem_unittest import Patcher

with Patcher() as patcher:
    # access the fake_filesystem object via patcher.fs
    patcher.fs.create_file('/foo/bar', contents='test')

    # the following code works on the fake filesystem
    with open('/foo/bar') as f:
        contents = f.read()

You can also initialize Patcher manually:

from fake_filesystem_unittest import Patcher

patcher = Patcher()
patcher.setUp()     # called in the initialization code
...
patcher.tearDown()  # somewhere in the cleanup code

Patch using unittest.mock (deprecated)

You can also use mock.patch() to patch the modules manually. This approach will only work for the directly imported modules, therefore it is not suited for testing larger code bases. As the other approaches are more convenient, this one is considered deprecated and will not be described in detail.

Customizing Patcher and TestCase

Both fake_filesystem_unittest.Patcher and fake_filesystem_unittest.TestCase provide a few additional arguments for fine-tuning. These are only needed if patching does not work for some module.

Note

If you need these arguments in PyTest, you have to use Patcher directly instead of the fs fixture. Alternatively, you can add your own fixture with the needed parameters (see pytest_plugin.py for a possible implementation).

modules_to_reload

This allows to pass a list of modules that shall be reloaded, thus allowing to patch modules not imported directly.

Pyfakefs automatically patches modules only if they are imported directly, e.g:

import os
import pathlib.Path

The following imports of os and pathlib.Path will not be patched by pyfakefs, however:

import os as my_os
from pathlib import Path

Note

There is one exception to that: importing os.path like from os import path will work, because it is handled by pyfakefs (see also patch_path below).

If adding the module containing these imports to modules_to_reload, they will be correctly patched.

modules_to_patch

This also allows patching modules that are not patched out of the box, in this case by adding a fake module implementation for a module name. The argument is a dictionary of fake modules mapped to the names to be faked. This can be used to fake modules imported as another name directly. For the os import above you could also use:

with Patcher(modules_to_patch={'my_os': fake_filesystem.FakeOsModule}):
    test_something()

For the second example (from pathlib import Path) the syntax is slightly different:

with Patcher(modules_to_patch={'pathlib.Path': MyFakePath}):
    test_something()

This will fake the class Path inside the module pathlib, if imported as Path. Here is an example of how to implement MyFakePath:

class MyFakePath():
    """Patches `pathlib.Path` by passing all calls to FakePathlibModule."""
    fake_pathlib = None

    def __init__(self, filesystem):
        if self.fake_pathlib is None:
            from pyfakefs.fake_pathlib import FakePathlibModule
            self.__class__.fake_pathlib = FakePathlibModule(filesystem)

    def __call__(self, *args, **kwargs):
        return self.fake_pathlib.Path(*args, **kwargs)

    def __getattr__(self, name):
        return getattr(self.fake_pathlib.Path, name)

patch_path

This is True by default, meaning that modules named path are patched as os.path. If this clashes with another module of the same name, it can be switched off (and imports like from os import path will not be patched).

additional_skip_names

This may be used to add modules that shall not be patched. This is mostly used to avoid patching the Python file system modules themselves, but may be helpful in some special situations.

use_dynamic_patch

If True (the default), dynamic patching after setup is used (for example for modules loaded locally inside of functions). Can be switched off if it causes unwanted side effects.

Using convenience methods

While pyfakefs can be used just with the standard Python file system functions, there are few convenience methods in fake_filesystem that can help you setting up your tests. The methods can be accessed via the fake_filesystem instance in your tests: Patcher.fs, the fs fixture in PyTest, or TestCase.fs.

File creation helpers

To create files, directories or symlinks together with all the directories in the path, you may use create_file(), create_dir() and create_symlink(), respectively.

create_file() also allows you to set the file mode and the file contents together with the encoding if needed. Alternatively, you can define a file size without contents - in this case, you will not be able to perform standard IO operations on the file (may be used to “fill up” the file system with large files).

from fake_filesystem_unittest import TestCase

class ExampleTestCase(TestCase):
    def setUp(self):
        self.setUpPyfakefs()

    def test_create_file(self):
        file_path = '/foo/bar/test.txt'
        self.fs.create_file(file_path, contents = 'test')
        with open(file_path) as f:
            self.assertEqual('test', f.read())

create_dir() behaves like os.makedirs(), but can also be used in Python 2.

Access to files in the real file system

If you want to have read access to real files or directories, you can map them into the fake file system using add_real_file(), add_real_directory() and add_real_paths(). They take a file path, a directory path, or a list of paths, respectively, and make them accessible from the fake file system. By default, the contents of the mapped files and directories are read only on demand, so that mapping them is relatively cheap. The access to the files is by default read-only, but even if you add them using read_only=False, the files are written only in the fake system (e.g. in memory). The real files are never changed.

add_real_file() and add_real_directory() also allow you to map a file or a directory tree into another location in the fake filesystem via the argument target_path.

from fake_filesystem_unittest import TestCase

class ExampleTestCase(TestCase):

    fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
    def setUp(self):
        self.setUpPyfakefs()
        # make the file accessible in the fake file system
        self.fs.add_real_directory(self.fixture_path)

    def test_using_fixture1(self):
        with open(os.path.join(self.fixture_path, 'fixture1.txt') as f:
            # file contents are copied to the fake file system
            # only at this point
            contents = f.read()

Handling mount points

Under Linux and MacOS, the root path (/) is the only mount point created in the fake file system. If you need support for more mount points, you can add them using add_mount_point().

Under Windows, drives and UNC paths are internally handled as mount points. Adding a file or directory on another drive or UNC path automatically adds a mount point for that drive or UNC path root if needed. Explicitly adding mount points shall not be needed under Windows.

A mount point has a separate device ID (st_dev) under all systems, and some operations (like rename) are not possible for files located on different mount points. The fake file system size (if used) is also set per mount point.

Setting the file system size

If you need to know the file system size in your tests (for example for testing cleanup scripts), you can set the fake file system size using set_disk_usage(). By default, this sets the total size in bytes of the root partition; if you add a path as parameter, the size will be related to the mount point (see above) the path is related to.

By default, the size of the fake file system is considered infinite. As soon as you set a size, all files will occupy the space according to their size, and you may fail to create new files if the fake file system is full.

from fake_filesystem_unittest import TestCase

class ExampleTestCase(TestCase):

    def setUp(self):
        self.setUpPyfakefs()
        self.fs.set_disk_usage(100)

    def test_disk_full(self):
        with open('/foo/bar.txt', 'w') as f:
            self.assertRaises(OSError, f.write, 'a' * 200)

To get the file system size, you may use get_disk_usage(), which is modeled after shutil.disk_usage().