From 50c162cfb46ecfea6557a5cd5f66d67203e586e7 Mon Sep 17 00:00:00 2001 From: Varun Chawla Date: Sat, 7 Feb 2026 17:14:33 -0800 Subject: [PATCH 1/2] Fix MockTransport not setting elapsed property MockTransport now automatically sets response.elapsed to timedelta(0) for both sync and async requests, matching the behavior of real transports and eliminating the need for boilerplate code in handlers. Previously, accessing response.elapsed on MockTransport responses would raise RuntimeError. Now it returns timedelta(0) by default, which is the expected behavior for mocked requests with no actual network I/O. Fixes #3712 --- httpx/_transports/mock.py | 3 +++ tests/client/test_client.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/httpx/_transports/mock.py b/httpx/_transports/mock.py index 8c418f59..9fd5ec68 100644 --- a/httpx/_transports/mock.py +++ b/httpx/_transports/mock.py @@ -1,5 +1,6 @@ from __future__ import annotations +import datetime import typing from .._models import Request, Response @@ -24,6 +25,7 @@ class MockTransport(AsyncBaseTransport, BaseTransport): response = self.handler(request) if not isinstance(response, Response): # pragma: no cover raise TypeError("Cannot use an async handler in a sync Client") + response.elapsed = datetime.timedelta() return response async def handle_async_request( @@ -40,4 +42,5 @@ class MockTransport(AsyncBaseTransport, BaseTransport): if not isinstance(response, Response): response = await response + response.elapsed = datetime.timedelta() return response diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 65783901..535c741f 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -460,3 +460,40 @@ def test_client_decode_text_using_explicit_encoding(): assert response.reason_phrase == "OK" assert response.encoding == "ISO-8859-1" assert response.text == text + + +def test_mock_transport_elapsed(): + """Test that MockTransport sets the elapsed property. + + Regression test for https://github.com/encode/httpx/issues/3712 + """ + def handler(request): + return httpx.Response(200, json={"text": "Hello, world!"}) + + transport = httpx.MockTransport(handler) + with httpx.Client(transport=transport) as client: + response = client.get("http://www.example.com") + assert response.status_code == 200 + # MockTransport should set elapsed to timedelta(0) + assert response.elapsed == timedelta(0) + # Accessing elapsed should not raise RuntimeError + assert isinstance(response.elapsed, timedelta) + + +@pytest.mark.anyio +async def test_async_mock_transport_elapsed(): + """Test that MockTransport sets the elapsed property for async requests. + + Regression test for https://github.com/encode/httpx/issues/3712 + """ + def handler(request): + return httpx.Response(200, json={"text": "Hello, world!"}) + + transport = httpx.MockTransport(handler) + async with httpx.AsyncClient(transport=transport) as client: + response = await client.get("http://www.example.com") + assert response.status_code == 200 + # MockTransport should set elapsed to timedelta(0) + assert response.elapsed == timedelta(0) + # Accessing elapsed should not raise RuntimeError + assert isinstance(response.elapsed, timedelta) From 324e16aab8289b3af001a2217ccfd54d0350e7fb Mon Sep 17 00:00:00 2001 From: Varun Chawla Date: Sat, 7 Feb 2026 18:41:59 -0800 Subject: [PATCH 2/2] Fix code formatting in test_client.py Add blank lines after docstrings in MockTransport elapsed tests to comply with Ruff formatting rules. --- tests/client/test_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 535c741f..90afc7bf 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -467,6 +467,7 @@ def test_mock_transport_elapsed(): Regression test for https://github.com/encode/httpx/issues/3712 """ + def handler(request): return httpx.Response(200, json={"text": "Hello, world!"}) @@ -486,6 +487,7 @@ async def test_async_mock_transport_elapsed(): Regression test for https://github.com/encode/httpx/issues/3712 """ + def handler(request): return httpx.Response(200, json={"text": "Hello, world!"})