How does the book demonstrate mocking in pytest? Provide examples of different ways to mock the preamble function.
The book demonstrates mocking in pytest by replacing the preamble() function from mod1.py with a mock so that summer() can be tested in isolation. It shows four variations in Example 12-5: mock.patch as a context manager with return_value set, a context manager that stores the mock object and assigns its return_value, a @mock.patch decorator that passes the mock as a test argument, and a decorator form where return_value is assigned inside the test body. It also demonstrates a fake/double approach using an environment variable and import switching.
The book uses a simple two-module example. mod1.py defines preamble(), which returns 'The sum is '. mod2.py defines summer(), which calls mod1.preamble() and appends the sum. To test just summer(), the book mocks preamble() so that it returns an empty string, allowing the test to assert that summer(5, 6) returns '11'. In Example 12-5, four test functions show different mocking styles. The first uses mock.patch('mod1.preamble', return_value='') as a context manager, so the mocked function is active only inside the with block. The second uses mock.patch('mod1.preamble') as a context manager, assigns the result to mock_preamble, and then sets mock_preamble.return_value = '' before calling summer(). The third uses @mock.patch('mod1.preamble', return_value='') as a decorator, with the mock passed as an argument named mock_preamble. The fourth uses @mock.patch('mod1.preamble') as a decorator, and inside the test sets mock_preamble.return_value = ''. All four tests pass, because the mock replaces the real preamble() whenever summer() is called. The book notes that the string name of the mocked item must match how it is referenced in the code under test. It then presents an alternative double/fake approach in which mod2.py checks an environment variable, such as os.getenv('UNIT_TEST'), and imports fake_mod1 as mod1 when testing, so summer() uses a fake preamble() that returns an empty string. This avoids writing mocks but requires adding the environment-variable check to the production module.
Key points
- Mocks are used to isolate the function under test from external functions like preamble().
- mock.patch can be used as a context manager with return_value set directly.
- mock.patch can also be used as a context manager with a mock object assigned and return_value set afterward.
- @mock.patch as a decorator can pass the mock as a test function argument.
- A decorator mock can be written with return_value in the decorator call or set inside the test body.
- The mocked target's string name must match the reference in the code being tested.
- An alternative fake/double method imports a fake module when an environment variable is set.
Related questions
FastAPI: Modern Python Web Development
Bill Lubanovic;
First Edition · O'Reilly Media, Inc.