Mocking and stubbing are often used interchangeably, but they’re genuinely distinct testing techniques serving different purposes — worth knowing the actual difference.
from unittest.mock import Mock
# STUB: provides canned, predetermined responses - you don't care HOW it's called,
# just that it returns the right data for the test to proceed
def get_weather_stub(city):
return {"temp": 22, "condition": "sunny"} # always the same, regardless of input
# MOCK: additionally verifies HOW it was called - genuinely useful for
# testing that a specific interaction actually happened
payment_mock = Mock()
process_order(order, payment_service=payment_mock)
payment_mock.charge.assert_called_once_with(amount=59.99, currency="EUR")
# This test FAILS if charge() was never called, or called with the wrong arguments -
# a stub alone couldn't verify this interaction happened at all
When to Use Which
- Stubs — when you just need a dependency to return specific data so the test can proceed (e.g., faking a database query result)
- Mocks — when the actual behavior under test IS the interaction itself (e.g., verifying a payment was genuinely charged, an email was genuinely sent)
The Overuse Trap
Mocking every single dependency, including simple, cheap-to-use real objects, produces tests that verify implementation details rather than genuine behavior — brittle tests that break on any internal refactor, even when the actual observable behavior hasn’t changed at all. Mock genuinely external, slow, or side-effecting dependencies (network calls, payment APIs); let simple, fast internal logic run for real wherever practical.