🧪 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 :
