Skip to content

Commit 101cacf

Browse files
authored
Merge pull request #547 from realpython/unittest-mock
Add example code for unittest.mock resurfacing
2 parents c0b2da3 + 0eafad7 commit 101cacf

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

unittest-mock/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Understanding the Python Mock Object Library
2+
3+
This folder contains code examples related to the RealPython tutorial on [Understanding the Python Mock Object Library](https://realpython.com/python-mock-library/).
4+
5+
The example code showcases some of the different use cases of `unittest.mock` in a single test file, `test_my_calendar.py`. When writing your own tests, keep in mind that readability counts and that your test code will be more readable if you keep one consistent approach to mocking.
6+
7+
## Installation
8+
9+
1. Create a Python virtual environment
10+
11+
```sh
12+
$ python -m venv ./venv
13+
$ source venv/bin/activate
14+
(venv) $
15+
```
16+
17+
2. Install the requirements
18+
19+
```sh
20+
(venv) $ pip install requests
21+
```
22+
23+
## Run the Tests
24+
25+
```sh
26+
(venv) $ python test_my_calendar.py
27+
```
28+
29+
All the tests should pass. Go ahead and play with the code examples, change them, break them, and practice your understanding of using `unittest.mock` for testing in Python.
30+
31+
## About the Author
32+
33+
Martin Breuss - Email: [email protected]
34+
35+
## License
36+
37+
Distributed under the MIT license. See ``LICENSE`` for more information.

unittest-mock/my_calendar.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from datetime import datetime
2+
3+
import requests
4+
5+
6+
def is_weekday():
7+
today = datetime.today()
8+
# Python's datetime library treats Monday as 0 and Sunday as 6
9+
return 0 <= today.weekday() < 5
10+
11+
12+
def get_holidays():
13+
r = requests.get("http://localhost/api/holidays")
14+
if r.status_code == 200:
15+
return r.json()
16+
return None

unittest-mock/test_my_calendar.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import datetime
2+
import unittest
3+
from unittest.mock import Mock, patch
4+
5+
import requests
6+
from my_calendar import get_holidays, is_weekday
7+
from requests.exceptions import Timeout
8+
9+
10+
class TestCalendar(unittest.TestCase):
11+
@classmethod
12+
def setUpClass(cls):
13+
cls.wednesday = datetime.datetime(year=2025, month=1, day=1)
14+
cls.sunday = datetime.datetime(year=2025, month=1, day=5)
15+
cls.holidays = {"12/25": "Christmas", "7/4": "Independence Day"}
16+
cls.response_setup_dict = {
17+
"json.return_value": TestCalendar.holidays,
18+
"status_code": 200,
19+
}
20+
21+
def log_request(self, url):
22+
"""Helper function that logs and returns a mock successful request."""
23+
print(f"Making a request to {url}.")
24+
print("Request received!")
25+
response_mock = Mock(**TestCalendar.response_setup_dict)
26+
return response_mock
27+
28+
@patch("my_calendar.datetime")
29+
def test_is_weekday_returns_true_on_weekdays(self, mock_datetime):
30+
mock_datetime.today.return_value = TestCalendar.wednesday
31+
self.assertTrue(is_weekday())
32+
33+
@patch("my_calendar.datetime")
34+
def test_is_weekday_returns_false_on_weekends(self, mock_datetime):
35+
mock_datetime.today.return_value = TestCalendar.sunday
36+
self.assertFalse(is_weekday())
37+
38+
# Example of patching only a specific object
39+
@patch.object(requests, "get", side_effect=requests.exceptions.Timeout)
40+
def test_get_holidays_timeout(self, mock_requests):
41+
with self.assertRaises(requests.exceptions.Timeout):
42+
get_holidays()
43+
44+
# Example of using the `with` statement with `patch()`
45+
def test_get_holidays_logging(self):
46+
with patch("my_calendar.requests") as mock_requests:
47+
mock_requests.get.side_effect = self.log_request
48+
self.assertEqual(get_holidays()["12/25"], "Christmas")
49+
50+
@patch("my_calendar.requests")
51+
def test_get_holidays_retry(self, mock_requests):
52+
response_mock = Mock(**TestCalendar.response_setup_dict)
53+
# Set the side effect of .get()
54+
mock_requests.get.side_effect = [Timeout, response_mock]
55+
# Test that the first request raises a Timeout
56+
with self.assertRaises(Timeout):
57+
get_holidays()
58+
# Now retry, expecting a successful response
59+
self.assertEqual(get_holidays()["12/25"], "Christmas")
60+
# Finally, assert .get() was called twice
61+
self.assertEqual(mock_requests.get.call_count, 2)
62+
63+
64+
if __name__ == "__main__":
65+
unittest.main()

0 commit comments

Comments
 (0)