Python Mocking & Stubbing – Simulate and Control Code Behavior in Tests
Introduction – Why Use Mocking & Stubbing?
In unit testing, you often need to test a piece of code in isolation. But what if that code:
- Connects to a database?
- Makes HTTP calls?
- Depends on slow, external services?
This is where mocking and stubbing come in.
With Python’s built-in unittest.mock module, you can:
- Replace real objects with controlled stand-ins
- Simulate return values, exceptions, and side effects
- Verify how functions are called
In this guide, you’ll learn:
- The difference between mocking and stubbing
- How to use
Mock,MagicMock, andpatch() - How to simulate return values and exceptions
- Best practices and common pitfalls
What Are Mocking and Stubbing?
| Term | Description |
|---|---|
| Stub | A simplified version of a function that returns fixed output |
| Mock | A fake object that records calls and can simulate complex behavior |
Stubs are passive (just return data), while mocks are interactive (track usage).
Getting Started with unittest.mock
from unittest.mock import Mock
Create a Simple Mock
mock_func = Mock()
mock_func.return_value = "Hello"
print(mock_func()) # Output: Hello
Setting Return Values and Side Effects
mock = Mock()
mock.get_data.return_value = [1, 2, 3]
mock.raise_error.side_effect = ValueError("Invalid data")
print(mock.get_data()) # [1, 2, 3]
mock.raise_error() # Raises ValueError
MagicMock – Smarter Mocks with Built-in Magic Methods
from unittest.mock import MagicMock
m = MagicMock()
m.__len__.return_value = 5
print(len(m)) # 5
MagicMock is a subclass of Mock with all dunder methods included.
Using patch() – Replace Objects Temporarily
Replace a Method During Test
from unittest.mock import patch
def fetch_user():
return "Real user data"
with patch('__main__.fetch_user', return_value="Mocked data"):
print(fetch_user()) # Mocked data
print(fetch_user()) # Real user data
patch() is perfect for mocking external dependencies, APIs, and class methods.
Patching Objects Inside Classes
class EmailService:
def send(self):
return "Email sent"
with patch.object(EmailService, 'send', return_value="Mocked email"):
service = EmailService()
print(service.send()) # Mocked email
Verifying Calls and Arguments
assert_called_with()
mock = Mock()
mock("Alice", 42)
mock.assert_called_with("Alice", 42)
call_args, call_count, call_args_list
mock = Mock()
mock(1)
mock(2)
print(mock.call_count) # 2
print(mock.call_args_list) # [call(1), call(2)]
Useful for verifying that functions were used correctly.
Real-World Use Case – Mocking API Call
import requests
from unittest.mock import patch
def get_data():
response = requests.get("https://api.example.com/data")
return response.json()
@patch("requests.get")
def test_get_data(mock_get):
mock_get.return_value.json.return_value = {"key": "value"}
result = get_data()
assert result == {"key": "value"}
No actual API request is made—pure unit testing!
Mocking vs Stubbing – Summary
| Feature | Stub | Mock |
|---|---|---|
| Returns fixed data | Yes | Yes |
| Tracks usage | No | Yes (assert_called_with) |
| Raises exceptions | Yes | Yes (side_effect) |
| Best for | Data setup | Behavior verification |
Best Practices
| Do This | Avoid This |
|---|---|
Use patch() as a context manager or decorator | Forgetting to stop the patch manually |
Verify arguments with assert_called_with() | Assuming mocks are always called |
Use side_effect for exceptions or sequences | Hardcoding return values only |
| Keep mocks focused on one behavior | Over-mocking everything |
Summary – Recap & Next Steps
Python’s unittest.mock gives you the power to test any part of your code in isolation—without relying on databases, APIs, or third-party services.
Key Takeaways:
- Use stubs for predictable outputs
- Use mocks to track function calls and simulate behavior
-
patch()helps temporarily replace modules, classes, or functions - Use
MagicMockwhen mocking magic methods (__len__,__getitem__, etc.)
Real-World Relevance:
Used in unit testing, CI/CD pipelines, test-driven development, and mock API testing.
FAQ – Python Mocking & Stubbing
What is the difference between Mock and MagicMock?
MagicMock includes default implementations for all magic methods like __str__, __len__, __getitem__, etc.
Should I mock everything in a test?
No. Only mock external dependencies—keep tests readable and relevant.
Can I simulate exceptions with mocks?
Yes, using side_effect:
mock.side_effect = ValueError("Boom!")
How do I test if a function was called?
Use:
mock.assert_called()
mock.assert_called_with(args)
Does mocking slow down tests?
No—it makes tests faster by removing external I/O.
Share Now :
