🎓 A1Learner
🔍

Python unittest.mock (Survey)

A mock is a fake object that records every call made on it. A test uses a mock for code that talks to the outside world.

A Mock records its calls

called tells you the method ran. call_args shows the last call.

from unittest.mock import Mock

sender = Mock()
sender.send("Hello!")
print(sender.send.called)
print(sender.send.call_count)
print(sender.send.call_args)

Set a return value

Tell the fake what to hand back, then use it like the real thing.

from unittest.mock import Mock

api = Mock()
api.get_price.return_value = 42
print(api.get_price("apple"))
print(api.get_price.called)

patch swaps a name for a while

Inside the block the name is fake. After the block it is real again.

from unittest.mock import patch

def get_name():
    return "real"

with patch("__main__.get_name", return_value="fake"):
    print(get_name())
print(get_name())

Check that nothing was called

This assert fails if the fake was used at all.

fake_sender.assert_not_called()

Example

import unittest
from unittest.mock import patch

def send_email(address, message):
    print("Real sending to", address)

def notify_user(address, message):
    if not address:
        return False
    send_email(address, message)
    return True

class TestNotify(unittest.TestCase):
    def test_notify_calls_sender_once(self):
        with patch("test_notifier.send_email") as fake:
            result = notify_user("ana@example.com", "Hi!")
            self.assertTrue(result)
            fake.assert_called_once_with("ana@example.com", "Hi!")

    def test_empty_address_sends_nothing(self):
        with patch("test_notifier.send_email") as fake:
            result = notify_user("", "Hi!")
            self.assertFalse(result)
            fake.assert_not_called()

    def test_message_goes_through_unchanged(self):
        with patch("test_notifier.send_email") as fake:
            notify_user("bo@example.com", "Meeting moved")
            fake.assert_called_once_with("bo@example.com", "Meeting moved")

if __name__ == "__main__":
    unittest.main()

Key points

  • Mock: a fake object that records every call made on it.
  • A mock accepts any call and returns another mock, unless you set a return value.
  • Use patch to swap one name for a fake during a single test.
  • Use assert_called_once_with to check the exact call your code made.
  • Mock what you do not own, like a sender, a clock, or a web service.
  • Mock sparingly.
  • A test full of mocks tests the mocks, not your code.
  • patch restores the real object when the with block ends.

In this example, the whole program lives in one file, test_notifier.py. The function notify_user calls the module-level send_email. Each test patches that name, so no real mail can leave. The patch target names the module, test_notifier, and then the function. The first test checks the exact address and message of the single call. The second test checks that an empty address sends nothing at all. Run the file with python3 -m unittest test_notifier. The Ran line also reports a varying time in seconds. OK means all three tests passed.

Note

Nothing stays swapped after the test.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Python Playground

Exercise

When is a mock the right tool in a test?