aboutsummaryrefslogtreecommitdiff
path: root/docs/autopatch.rst
blob: 66d6a221ea1b986c2e27975446afb585fbf1a23e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
.. _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.

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.