Writing Resilient Python Unit Tests: Beyond the Basics
Overview of Reliable Unit Testing
Unit testing validates the behavior of small, isolated code fragments, typically individual functions or methods. These tests serve as a critical safety net during refactoring, ensuring that modifications in one area don't inadvertently break unrelated logic. Beyond catching bugs, well-crafted tests act as a live specification of how your system should behave. While Python includes a built-in unittest module, the industry standard has shifted toward pytest due to its readable syntax and powerful feature set.
Prerequisites
To follow this guide, you should have a solid grasp of Python fundamentals, including classes and decorators. Familiarity with the pip package manager and basic command-line operations is necessary. You should also understand the basics of HTTP requests, as our examples involve simulating API interactions.
Key Libraries & Tools
- pytest: A framework that simplifies writing small tests while scaling to support complex functional testing.
- httpx: A next-generation HTTP client for Python used in our examples to fetch weather data.
- unittest.mock: A standard library module that allows you to replace parts of your system under test with mock objects.
Code Walkthrough: Handling External Dependencies
Testing code that relies on external APIs, such as a WeatherService, is challenging because you cannot perform real HTTP requests during a unit test. You must replace the network call with a controlled response.

Implementation with Monkey Patching
Monkey patching dynamically replaces a function at runtime. In the following example, we replace httpx.get with a fake version that returns pre-defined data.
import pytest
import httpx
from weather import WeatherService
def test_get_temperature_with_patch(monkeypatch):
def fake_get(url, params=None):
class FakeResponse:
def raise_for_status(self):
return None
def json(self):
return {"current": {"temp": 19}}
return FakeResponse()
monkeypatch.setattr(httpx, "get", fake_get)
service = WeatherService(api_key="test_key")
assert service.get_temperature("Amsterdam") == 19
Implementation with MagicMock
The MagicMock class from unittest.mock offers a cleaner alternative to manual fake classes. It allows you to define return values and verify how many times a method was called.
from unittest.mock import MagicMock, patch
def test_with_mock():
mock_response = MagicMock()
mock_response.json.return_value = {"current": {"temp": 25}}
with patch("httpx.get", return_value=mock_response) as mock_get:
service = WeatherService(api_key="test_key")
temp = service.get_temperature("Utrecht")
assert temp == 25
mock_get.assert_called_once()
Syntax Notes: Pytest Features
- Fixtures: Use the
@pytest.fixturedecorator to define reusable setup code. Passing the fixture name as an argument to a test function automatically injects the object. - Parametrization: Use
@pytest.mark.parametrizeto run the same test logic against multiple sets of data without duplicating code. - Exception Testing: Use
with pytest.raises(ExceptionType):to verify that your code handles errors correctly.
Refactoring for Testability
Direct dependencies on libraries like httpx make testing rigid. By using Dependency Injection, you pass a client object into the WeatherService constructor. This allows you to swap the real HTTP client for a mock client during testing without ever touching monkey patches. Good design and testability go hand in hand; if a function is hard to test, it usually needs a better architectural approach.
Tips & Gotchas
- Python Path: Ensure your
pyproject.tomlincludes the correctpythonpath. Without it, pytest may fail to find your local modules. - Assert Quantity: Aim for one logical assertion per test to maintain clarity. If a test fails, you should know exactly why immediately.
- Skip & XFail: Use
pytest.mark.skipfor temporary bypasses andpytest.mark.xfailfor known bugs that are being tracked but not yet fixed.
- pytest
- 38%· software
- httpx
- 25%· software
- Python
- 25%· languages
- Squarespace
- 13%· software

How to Write Great Unit Tests in Python
WatchArjanCodes // 22:57
On this channel, I post videos about programming and software design to help you take your coding skills to the next level. I'm an entrepreneur and a university lecturer in computer science, with more than 20 years of experience in software development and design. If you're a software developer and you want to improve your development skills, and learn more about programming in general, make sure to subscribe for helpful videos. I post a video here every Friday. If you have any suggestion for a topic you'd like me to cover, just leave a comment on any of my videos and I'll take it under consideration. Thanks for watching!