The Problem: Mocking Creates Fragile Tests

Mocking external APIs is a common approach for testing—but it’s flawed:

Example: The Mocking Problem in Action

Original Code

Uploads a file to the file.io API.

GitHub Repo

src/file_uploader.py

import requests

def upload_file(file_path):
    with open(file_path, "rb") as file:
        response = requests.post("<https://file.io>", files={"file": file})
        response.raise_for_status()
        return response.json()

if __name__ == "__main__":
    print(upload_file("sample.txt"))

Screenshot 2024-11-29 at 08.47.22.png

Mock Test

This works as long as you use requests.post.

tests/test_file_uploader.py

from unittest.mock import patch, Mock, ANY
from src.file_uploader_refactor import upload_file

@patch("src.file_uploader_refactor.requests.post")
def test_upload_file(mock_post):
    mock_response = Mock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"success": True, "id": "TEST"}
    mock_post.return_value = mock_response

    result = upload_file("sample.txt")
    assert result["id"] == "TEST"
    mock_post.assert_called_once_with("<https://file.io>", files={"file": ANY})

Screenshot 2024-11-29 at 09.24.45.png

Refactoring Breaks the Test

Let’s switch to requests.Session for better performance. The functionality is the same, but...