Skip to content

Commit eded498

Browse files
🧪 Add test for check_error (#42)
* 🧪 Add test for check_error Added comprehensive unit tests for the `enapter.http.api.errors.check_error` function. Covered all logical branches, including successful responses, generic server errors (non-JSON payloads triggering raise_for_status), and API-specific errors (single and multiple errors from DTO). Also added coverage for empty payloads parsing. Co-authored-by: rnovatorov <[email protected]> * 🎨 Fix black formatting in test_errors.py Ran `black tests/unit/test_http/test_api/test_errors.py` to fix formatting violations that were causing the CI `make check` step to fail. Now lines involving `httpx.Response` object creation are properly wrapped to respect the line length limit. Co-authored-by: rnovatorov <[email protected]> * 🧪 Add test verifying `check_error` reads response body Addresses PR feedback by adding `test_check_error_reads_body` which verifies that `response.aread()` is called when `response.is_success` is False, ensuring the body is completely read for streamed responses. Also fixed PEP8 import order. Co-authored-by: rnovatorov <[email protected]> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 57a9f74 commit eded498

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from unittest.mock import AsyncMock
2+
3+
import httpx
4+
import pytest
5+
6+
from enapter.http.api.errors import Error, MultiError, check_error
7+
8+
9+
@pytest.mark.asyncio
10+
async def test_check_error_success():
11+
"""Test that check_error does nothing when response is successful."""
12+
response = httpx.Response(
13+
status_code=200, request=httpx.Request("GET", "https://example.com")
14+
)
15+
await check_error(response)
16+
17+
18+
@pytest.mark.asyncio
19+
async def test_check_error_non_json():
20+
"""Test that check_error calls raise_for_status when response is not JSON."""
21+
response = httpx.Response(
22+
status_code=500,
23+
content=b"Internal Server Error",
24+
request=httpx.Request("GET", "https://example.com"),
25+
)
26+
with pytest.raises(httpx.HTTPStatusError):
27+
await check_error(response)
28+
29+
30+
@pytest.mark.asyncio
31+
async def test_check_error_api_error_single():
32+
"""Test that check_error raises a single Error when one is present in DTO."""
33+
dto = {
34+
"errors": [
35+
{
36+
"message": "Device not found",
37+
"code": "DEVICE_NOT_FOUND",
38+
"details": {"device_id": "test_device"},
39+
}
40+
]
41+
}
42+
response = httpx.Response(
43+
status_code=404, json=dto, request=httpx.Request("GET", "https://example.com")
44+
)
45+
with pytest.raises(Error) as exc_info:
46+
await check_error(response)
47+
48+
assert exc_info.value.message == "Device not found"
49+
assert exc_info.value.code == "DEVICE_NOT_FOUND"
50+
assert exc_info.value.details == {"device_id": "test_device"}
51+
52+
53+
@pytest.mark.asyncio
54+
async def test_check_error_api_error_multiple():
55+
"""Test that check_error raises MultiError when multiple are present in DTO."""
56+
dto = {
57+
"errors": [
58+
{"message": "Invalid parameter A", "code": "INVALID_PARAM"},
59+
{"message": "Invalid parameter B", "code": "INVALID_PARAM"},
60+
]
61+
}
62+
response = httpx.Response(
63+
status_code=400, json=dto, request=httpx.Request("GET", "https://example.com")
64+
)
65+
with pytest.raises(MultiError) as exc_info:
66+
await check_error(response)
67+
68+
assert len(exc_info.value.errors) == 2
69+
assert exc_info.value.errors[0].message == "Invalid parameter A"
70+
assert exc_info.value.errors[1].message == "Invalid parameter B"
71+
72+
73+
def test_error_from_dto_empty():
74+
"""Test Error.from_dto with minimal fields."""
75+
err = Error.from_dto({})
76+
assert err.message == "<no message>"
77+
assert err.code is None
78+
assert err.details is None
79+
80+
81+
def test_multi_error_from_dto_empty_list():
82+
"""Test MultiError.from_dto raises ValueError on empty error list."""
83+
with pytest.raises(ValueError, match="empty error list"):
84+
MultiError.from_dto({"errors": []})
85+
86+
87+
@pytest.mark.asyncio
88+
async def test_check_error_reads_body():
89+
"""Test that check_error reads the response body."""
90+
response = httpx.Response(
91+
status_code=500,
92+
content=b"Internal Server Error",
93+
request=httpx.Request("GET", "https://example.com"),
94+
)
95+
response.aread = AsyncMock()
96+
with pytest.raises(httpx.HTTPStatusError):
97+
await check_error(response)
98+
99+
response.aread.assert_awaited_once()

0 commit comments

Comments
 (0)