šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Python Mocking with unittest.mock

unittest.mock's Mock, patch, and the discipline of mocking at the right boundary — isolating a test from slow, unpredictable, or unavailable real dependencies.

⚔ Total XP: 0|šŸ’» python XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Core logic.

Quick Quiz //

What does mock_logger.info.assert_called_once_with(...) verify, that checking the function's RETURN VALUE alone would not?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

A test that hits a real database, calls a real external API, or depends on the current time isn't reliably testing your code's logic — it's testing the availability and behavior of everything it touches. Mocking replaces those real dependencies with controlled, predictable substitutes, and this lesson covers doing it correctly.

1Why Mock: Isolating a Unit From Its Dependencies

A test for get_current_price that genuinely calls external_api.fetch_price() — a real network call to an external service — has several real problems bundled together: it's slow (network latency dominates the test's runtime), it's flaky (the external service being briefly unavailable makes the test fail for reasons entirely unrelated to whether your own code is correct), it may cost real money or consume a rate-limited quota, and it fundamentally tests the *external service's* current behavior and availability as much as it tests your own function's logic.

unittest.mock.patch(), used as a context manager (or decorator), replaces the real fetch_price function with a Mock object for the duration of the test — return_value=150.25 configures that Mock to return 150.25 whenever it's called, with no actual network call ever happening. This isolates the test to verifying *your own code's logic* — does get_current_price correctly process and return whatever fetch_price gives it? — completely independent of whether the real external API happens to be available, correct, or fast at the moment the test runs.

This isolation is the entire philosophical point of *unit* testing, as distinct from integration testing: a unit test should verify one specific piece of logic in isolation, with its dependencies replaced by controlled, predictable substitutes — mocking is the standard mechanism for achieving that isolation whenever a dependency is genuinely external, slow, expensive, or non-deterministic (like the current time, or random number generation).

āœ•
—
+
from unittest.mock import patch

def get_current_price(symbol: str) -> float:
    return external_api.fetch_price(symbol)  # a real, slow, external call

def test_get_current_price():
    with patch("myapp.external_api.fetch_price", return_value=150.25) as mock_fetch:
        price = get_current_price("AAPL")
        assert price == 150.25
        mock_fetch.assert_called_once_with("AAPL")  # verify HOW it was called too
localhost:3000
Isolated, Fast, Deterministic
patch("...fetch_price", return_value=150.25)
No real network call — fast, reliable, tests only your own logic

2Verifying Interactions, Not Just Return Values

Some behavior worth testing isn't reflected in a function's return value at all — whether process_order correctly logs an informational message, whether it calls a payment gateway with exactly the right arguments, whether it does *not* accidentally trigger an error notification when nothing actually went wrong. A Mock object automatically records every call made to it — the arguments it was called with, how many times it was called — and this recorded history is inspectable and assertable after the code under test has run.

mock_logger.info.assert_called_once_with(f"Processing order {order.id}") verifies not just that *some* logging happened, but that .info() specifically (not .error() or .warning()) was called exactly once, with precisely that expected message — a much stronger, more specific assertion than merely checking the function's return value could ever provide, since the return value tells you nothing about what the function did *along the way*.

This 'verify the interaction, not just the outcome' capability is precisely why Mock objects are more powerful than simply stubbing a dependency with a plain fake function that returns a fixed value — assert_called_with(), call_count, call_args, and related Mock attributes let a test assert on the *shape* of how your code used a dependency, catching bugs (a missing log call, an accidentally duplicated API call, a wrong argument passed to a critical downstream function) that a return-value-only test would never detect.

āœ•
—
+
from unittest.mock import Mock

mock_logger = Mock()
process_order(order, logger=mock_logger)

mock_logger.info.assert_called_once_with(f"Processing order {order.id}")
assert mock_logger.error.call_count == 0  # verify NO error was logged
localhost:3000
Interaction Assertions
mock_logger.info.assert_called_once_with(...)
Verifies HOW the code used its dependency, not just what it returned

3Patch Where It's Looked Up: A Genuine, Common Gotcha

unittest.mock.patch(target) takes a string identifying exactly *where a name is looked up from* — and this is subtly, importantly different from where that name was *originally defined*, a distinction that trips up even experienced developers regularly enough that it's documented explicitly in unittest.mock's own official documentation as the single most common mistake.

When myapp/service.py does from myapp.external_api import fetch_price, Python evaluates that import once, at module-load time, and binds the name fetch_price directly into service.py's own module namespace — service.py now has its *own* independent reference to that function object, entirely separate from the reference still living in myapp.external_api's namespace. Patching myapp.external_api.fetch_price replaces the reference in external_api's namespace, but service.py's already-copied reference is completely unaffected by that change — get_current_price, defined in service.py, still calls its own local fetch_price reference, the original, unpatched function.

The fix is patching "myapp.service.fetch_price" — the name exactly as it's looked up from *within the module actually calling it*, not the module where it was originally defined. The general rule to internalize, stated precisely: always patch the name in the namespace of the module that *uses* it, not the namespace of the module that *defines* it — these are frequently, but not always, the same, and confusing the two produces a test that silently continues calling the real, unpatched dependency.

āœ•
—
+
# myapp/service.py
from myapp.external_api import fetch_price  # imported INTO this module's namespace

def get_current_price(symbol):
    return fetch_price(symbol)

# WRONG: patches the ORIGINAL location, but service.py already has its own reference
# patch("myapp.external_api.fetch_price")

# CORRECT: patch where it's actually LOOKED UP -- inside service.py's namespace
# patch("myapp.service.fetch_price")
localhost:3000
The Critical Distinction
patch("myapp.service.fetch_price")
Patch where it's LOOKED UP (used), not where it was originally defined

4Step-by-Step Breakdown

A unit test that calls a real payment API is slow, flaky, costs real money, and tests the payment provider's uptime as much as your own code. Mocking fixes all four problems at once.

unittest.mock.patch() replaces a real object with a Mock for the duration of a test -- the real function is never actually called.

A Mock object records every call made to it -- assert_called_with() and call_count let you verify your code interacted with a dependency CORRECTLY, not just that it produced the right output.

Checkpoint: What does mock_logger.info.assert_called_once_with(...) verify, that checking the function's RETURN VALUE alone would not?

  • →That the code under test actually called the logger correctly, with the exact expected arguments — not just what the function ultimately returned
  • →That the logging call completed within an acceptable time limit

Patch where the name is LOOKED UP, not where it's originally defined -- a common, confusing gotcha with patch().

Checkpoint: Why must you patch("myapp.service.fetch_price") rather than patch("myapp.external_api.fetch_price"), given that service.py imports fetch_price directly?

  • →Once service.py does 'from myapp.external_api import fetch_price', service.py has its OWN reference to the function in its own namespace — that's the reference that must be patched
  • →This is an arbitrary syntax requirement with no underlying technical reason

Mocking isolates a unit from its dependencies; Parameterized Tests covers running the same test logic against many different inputs efficiently.

Verify a Real Mock Call. Finish send_notification(): Mock() records every call made to it.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported (via server-side Python execution).

FirefoxSupported

Fully supported (via server-side Python execution).

SafariSupported

Fully supported (via server-side Python execution).

EdgeSupported

Fully supported (via server-side Python execution).

Best Practices

Mock genuinely external, slow, or non-deterministic dependencies, not your own well-tested internal logic

Mocking exists to isolate a test from things outside your control (network calls, the current time, randomness) — mocking your own internal functions extensively can hide real integration bugs between the pieces you're mocking away.

Always patch the name where it is used (looked up), not where it was originally defined

This is the single most common mocking mistake — a `from X import Y` import creates a separate reference in the importing module's own namespace, which must be patched directly.

Frequent Bugs

THE BUG

Patching a dependency at its original definition location instead of where the code under test actually imports and uses it, resulting in a test that silently continues calling the real, unpatched function.

THE FIX

Patch the exact name as it is looked up from within the module actually calling it — typically module_under_test.imported_name, not original_module.imported_name.

Real-World Examples

Testing an Order-Processing Function Without a Real Payment Gateway

A function processes an order by calling a payment gateway and logging the result — the test needs to verify this logic without making a real charge or depending on the gateway's actual availability.

from unittest.mock import patch, Mock

def test_process_order_charges_correct_amount():
    with patch("myapp.orders.payment_gateway") as mock_gateway:
        mock_gateway.charge.return_value = {"status": "success", "id": "ch_123"}
        result = process_order(order_id=42, amount=99.99)
        mock_gateway.charge.assert_called_once_with(amount=99.99)
        assert result["status"] == "success"

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Patching a function at its original definition module instead of at the module that imports and actually calls it, resulting in the real function still being called despite the patch appearing to succeed.

# Wrong: patches the original location, service.py's own reference is untouched with patch("myapp.external_api.fetch_price", return_value=150.25): get_current_price("AAPL") # still calls the REAL fetch_price # Correct: patches where it's actually looked up and called from with patch("myapp.service.fetch_price", return_value=150.25): get_current_price("AAPL") # correctly uses the mock

The Solution //

Patch the name exactly where it is looked up from — the namespace of the module under test that calls the dependency, not the module where the dependency was originally defined.

Lesson Glossary

[01]unittest.mock.Mock

A configurable object that records every call made to it, standing in for a real dependency during a test.

Code Preview
// unittest.mock.Mock context

[02]unittest.mock.patch

A function/context manager/decorator that temporarily replaces a named object with a Mock for the duration of a test.

Code Preview
// unittest.mock.patch context

[03]Interaction verification

Asserting on HOW a mocked dependency was called (arguments, call count), rather than only checking the code's return value.

Code Preview
// Interaction verification context

[04]Patch target resolution

The rule that patch() must target the name as looked up from the module using it, not the module where it was originally defined.

Code Preview
// Patch target resolution context

Continue Learning