Python Mocking and Stubbing
When writing tests in Python, you often need to deal with:
- External APIs
- Databases
- File systems
- Network requests
But testing real external systems can be:
- Slow
- Unreliable
- Expensive
- Hard to control
This is where Mocking and Stubbing come in.
They allow you to simulate real components without actually using them.
What is Mocking?
Mocking means creating a fake object that imitates a real object’s behavior.
A mock can:
- Simulate function calls
- Return predefined values
- Track how it was used
What is Stubbing?
Stubbing is a simpler form of mocking where you:
- Replace a function or method
- Return fixed data
- Do not track behavior
Difference Between Mocking and Stubbing
| Feature | Mocking | Stubbing |
|---|---|---|
| Tracks calls | Yes | No |
| Returns fake data | Yes | Yes |
| Verifies behavior | Yes | No |
| Complexity | Higher | Lower |
Why Use Mocking?
Mocking helps you:
- Isolate code during testing
- Avoid external dependencies
- Speed up tests
- Simulate edge cases
- Improve reliability
The unittest.mock Module
Python provides built-in support for mocking:
from unittest.mock import Mock, patch1. Creating a Simple Mock
from unittest.mock import Mock
mock = Mock()
mock.return_value = 10
print(mock())Output
102. Mocking a Function
from unittest.mock import Mock
def get_data():
return "real data"
get_data = Mock(return_value="fake data")
print(get_data())Output
fake data3. Using patch() for Stubbing
The patch() function replaces real objects temporarily.
from unittest.mock import patch
def get_price():
return 100Test with Patch
with patch("__main__.get_price", return_value=50):
print(get_price())Output
504. Mocking API Calls
from unittest.mock import patch
import requests
def fetch_data():
response = requests.get("https://api.example.com")
return response.json()Test with Mock
with patch("requests.get") as mock_get:
mock_get.return_value.json.return_value = {"status": "ok"}
print(fetch_data())Output
{'status': 'ok'}5. Checking Method Calls
Mocks can track usage.
from unittest.mock import Mock
mock = Mock()
mock("hello")
print(mock.called)Output
True6. Checking Call Arguments
mock = Mock()
mock(10, 20)
print(mock.call_args)Output
call(10, 20)7. Stubbing Database Calls
def get_user():
return {"name": "real user"}Test Stub
with patch("__main__.get_user", return_value={"name": "mock user"}):
print(get_user())Output
{'name': 'mock user'}8. Mocking File Operations
from unittest.mock import mock_open, patch
with patch("builtins.open", mock_open(read_data="file content")):
with open("file.txt") as f:
print(f.read())Output
file content9. Stubbing Time Functions
from unittest.mock import patch
import time
with patch("time.time", return_value=1000):
print(time.time())Output
100010. Assertions with Mocks
from unittest.mock import Mock
mock = Mock()
mock()
mock.assert_called_once()11. assert_called_with()
mock = Mock()
mock(5)
mock.assert_called_with(5)12. Real-World Use Cases
Mocking and stubbing are used in:
- Unit testing
- API testing
- Database testing
- Microservices testing
- CI/CD pipelines
- Test automation frameworks
Advantages
- Faster tests
- No external dependency
- Controlled test environment
- Easier debugging
- Better test isolation
Common Mistakes
Over-mocking
Mocking everything can make tests meaningless.
Not Testing Real Behavior
mock.return_value = "anything"This may hide real bugs.
Incorrect Patch Path
Always patch where the function is used, not where it is defined.
Best Practices
- Mock only external systems
- Keep tests simple
- Verify important calls
- Use patch carefully
- Combine mocks with real logic
Summary
Mocking and stubbing are essential testing techniques in Python. They help simulate real-world dependencies, making unit tests faster, safer, and more reliable.
Conclusion
Python’s unittest.mock module provides powerful tools for mocking and stubbing. By mastering these techniques, developers can build robust test suites that ensure code quality and stability without relying on external systems.


0 Comments