| .. _auto_patch: |
| |
| Automatically find and patch file functions and modules |
| ======================================================= |
| The ``fake_filesystem_unittest`` module automatically finds all real file |
| functions and modules, and stubs them out with the fake file system functions and modules. |
| The pyfakefs source code contains files that demonstrate this usage model: |
| |
| - ``example.py`` is the software under test. In production, it uses the |
| real file system. |
| - ``example_test.py`` tests ``example.py``. During testing, the pyfakefs fake |
| file system is used by ``example_test.py`` and ``example.py`` alike. |
| |
| .. note:: This example uses the Python ``unittest`` module for testing, but the |
| functionality is similar if using the ``fs`` fixture in ``pytest``, |
| the ``patchfs`` decorator, or the ``Patcher`` class. |
| |
| |
| Software Under Test |
| ------------------- |
| ``example.py`` contains a few functions that manipulate files. For instance: |
| |
| .. code:: python |
| |
| def create_file(path): |
| """Create the specified file and add some content to it. Use the open() |
| built in function. |
| |
| For example, the following file operations occur in the fake file system. |
| In the real file system, we would not even have permission to write /test: |
| |
| >>> os.path.isdir('/test') |
| False |
| >>> os.mkdir('/test') |
| >>> os.path.isdir('/test') |
| True |
| >>> os.path.exists('/test/file.txt') |
| False |
| >>> create_file('/test/file.txt') |
| >>> os.path.exists('/test/file.txt') |
| True |
| >>> with open('/test/file.txt') as f: |
| ... f.readlines() |
| ["This is test file '/test/file.txt'.\\n", 'It was created using the open() function.\\n'] |
| """ |
| with open(path, "w") as f: |
| f.write("This is test file '{}'.\n".format(path)) |
| f.write("It was created using the open() function.\n") |
| |
| No functional code in ``example.py`` even hints at a fake file system. In |
| production, ``create_file()`` invokes the real file functions ``open()`` and |
| ``write()``. |
| |
| Unit Tests and Doctests |
| ----------------------- |
| ``example_test.py`` contains unit tests for ``example.py``. ``example.py`` |
| contains the doctests, as you can see above. |
| |
| The module ``fake_filesystem_unittest`` contains code that finds all real file |
| functions and modules, and stubs these out with the fake file system functions |
| and modules: |
| |
| .. code:: python |
| |
| import os |
| import unittest |
| from pyfakefs import fake_filesystem_unittest |
| |
| # The module under test is example: |
| import example |
| |
| Doctests |
| ~~~~~~~~ |
| ``example_test.py`` defines ``load_tests()``, which runs the doctests in |
| ``example.py``: |
| |
| .. code:: python |
| |
| def load_tests(loader, tests, ignore): |
| """Load the pyfakefs/example.py doctest tests into unittest.""" |
| return fake_filesystem_unittest.load_doctests(loader, tests, ignore, example) |
| |
| |
| Everything, including all imported modules and the test, is stubbed out |
| with the fake filesystem. Thus you can use familiar file functions like |
| ``os.mkdir()`` as part of your test fixture and they too will operate on the |
| fake file system. |
| |
| Unit Test Class |
| ~~~~~~~~~~~~~~~ |
| Next comes the ``unittest`` test class. This class is derived from |
| ``fake_filesystem_unittest.TestCase``, which is in turn derived from |
| ``unittest.TestClass``: |
| |
| .. code:: python |
| |
| class TestExample(fake_filesystem_unittest.TestCase): |
| def setUp(self): |
| self.setUpPyfakefs() |
| |
| def tearDown(self): |
| # It is no longer necessary to add self.tearDownPyfakefs() |
| pass |
| |
| def test_create_file(self): |
| """Test example.create_file()""" |
| # The os module has been replaced with the fake os module so all of the |
| # following occurs in the fake filesystem. |
| self.assertFalse(os.path.isdir("/test")) |
| os.mkdir("/test") |
| self.assertTrue(os.path.isdir("/test")) |
| |
| self.assertFalse(os.path.exists("/test/file.txt")) |
| example.create_file("/test/file.txt") |
| self.assertTrue(os.path.exists("/test/file.txt")) |
| |
| ... |
| |
| |
| Just add ``self.setUpPyfakefs()`` in ``setUp()``. You need add nothing to |
| ``tearDown()``. Write your tests as usual. From ``self.setUpPyfakefs()`` to |
| the end of your ``tearDown()`` method, all file operations will use the fake |
| file system. |