When a function talks to time, random, or a file you do not want to touch, patch it. unittest.mock replaces that name for the duration of the test.
Goal
Patch time.time and json.load so tests stay deterministic.
Patch a clock
import time
import unittest
from unittest.mock import patch
def stamp(city):
return f"{city}@{int(time.time())}"
class StampTests(unittest.TestCase):
@patch("time.time", return_value=1_700_000_000)
def test_stamp(self, _mocked):
self.assertEqual(stamp("Nairobi"), "Nairobi@1700000000")
suite = unittest.defaultTestLoader.loadTestsFromTestCase(StampTests)
result = unittest.TextTestRunner(verbosity=2).run(suite)
print("ok" if result.wasSuccessful() else "failed")Patch json.load
import json
import unittest
from unittest.mock import patch
def load_city(path):
with open(path, encoding="utf-8") as handle:
return json.load(handle)["city"]
class ConfigTests(unittest.TestCase):
@patch("json.load", return_value={"city": "Mombasa"})
@patch("builtins.open")
def test_load_city(self, _open, _load):
self.assertEqual(load_city("config.json"), "Mombasa")
suite = unittest.defaultTestLoader.loadTestsFromTestCase(ConfigTests)
result = unittest.TextTestRunner(verbosity=2).run(suite)
print("ok" if result.wasSuccessful() else "failed")json.load returns a dict, so no real file is read. open is still patched so the with block does not hit disk.
Tip
Patch where the name is used, not where it is defined. If kiosk.py does from json import load, patch kiosk.load.