Skip to content

Commit f7a822d

Browse files
committed
docs: added docs to util functions
1 parent d37d34e commit f7a822d

File tree

4 files changed

+47
-4
lines changed

4 files changed

+47
-4
lines changed

backend/test/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ async def test_session():
5656
async def create_test_client(
5757
test_session: AsyncSession,
5858
) -> CreateClientCallable:
59+
"""Fixture to create test HTTP clients with different authentication roles."""
60+
5961
async def _create_test_client(role: StringRole | None):
6062
async def override_get_session():
6163
yield test_session
@@ -136,14 +138,12 @@ def mock_gmaps() -> MagicMock:
136138

137139
@pytest.fixture()
138140
def mock_place():
139-
"""Mock for Google Maps places.place API."""
140141
with patch("src.modules.location.location_service.places.place") as mock:
141142
yield mock
142143

143144

144145
@pytest.fixture()
145146
def mock_autocomplete():
146-
"""Mock for Google Maps places.places_autocomplete API."""
147147
with patch("src.modules.location.location_service.places.places_autocomplete") as mock:
148148
yield mock
149149

backend/test/utils/http/assertions.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Utility functions for asserting HTTP responses in tests."""
2+
13
from typing import Any, Optional, TypeVar, get_args, get_origin, overload
24

35
from fastapi import HTTPException
@@ -26,6 +28,19 @@ def assert_res_success(
2628
*,
2729
status: Optional[int] = 200,
2830
) -> T | list[T]:
31+
"""
32+
Assert that a response is a successful response. Validates and converts to the expected model type.
33+
34+
Args:
35+
res: The HTTP response to check
36+
ExpectedModel: The expected Pydantic model type (or list of model type) of the response data
37+
status: Optional expected HTTP status code (default 200)
38+
39+
Returns:
40+
The response data converted to the expected model type
41+
e.g. `assert_res_success(res, User)` returns `User`
42+
`assert_res_success(res, [User])` returns `list[User]`
43+
"""
2944
if status is not None:
3045
assert res.status_code == status, (
3146
f"Expected status {status}, got {res.status_code}. Response: {res.text}"
@@ -44,14 +59,17 @@ def assert_res_success(
4459
assert data is not None, "Expected response data but got None"
4560

4661
model_origin = get_origin(ExpectedModel)
62+
63+
# List model case
4764
if model_origin is list:
4865
assert isinstance(data, list), f"Expected list response but got {type(data).__name__}"
4966

67+
# Get the model type inside the list
5068
args = get_args(ExpectedModel)
5169
assert args is not None, "Expected type args for list model but got None"
5270
assert len(args) > 0, "Expected at least one type arg for list model but got empty args"
53-
5471
inner_model = args[0]
72+
5573
inner_fields = set(inner_model.model_fields.keys())
5674
for item in data:
5775
extra = set(item.keys()) - inner_fields
@@ -69,6 +87,16 @@ def assert_res_success(
6987

7088

7189
def assert_res_failure(res: Response, expected_error: HTTPException) -> dict[str, Any]:
90+
"""
91+
Assert that a response is a failure response matching the expected HTTPException.
92+
93+
Args:
94+
res: The HTTP response to check
95+
expected_error: The expected HTTPException instance representing the error
96+
97+
Returns:
98+
The response data dict containing the error details
99+
"""
72100
assert res.status_code == expected_error.status_code, (
73101
f"Expected status {expected_error.status_code}, got {res.status_code}. Response: {res.text}"
74102
)

backend/test/utils/http/test_templates.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@
1010

1111

1212
def generate_auth_required_tests(*params: tuple[set[StringRole], str, str, dict | None]):
13+
"""Generate authentication and authorization tests for HTTP endpoints.
14+
15+
Ensures that allowed roles can access the endpoint, disallowed roles are forbidden,
16+
and unauthenticated requests are unauthorized.
17+
18+
Args:
19+
params: A variable number of tuples, each containing:
20+
- allowed_roles (set[StringRole]): Roles allowed to access the endpoint.
21+
- method (str): The HTTP method (e.g., "GET", "POST").
22+
- path (str): The endpoint path (e.g., "/api/resource").
23+
- body (dict | None): The request body for methods like POST or PUT.
24+
"""
25+
1326
@pytest.mark.parametrize("allowed_roles, method, path, body", params)
1427
@pytest.mark.asyncio
1528
async def test_authentication(

backend/test/utils/resource_test_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ class EntityProtocl[DtoModel: BaseModel](Protocol):
1111
"""Protocol for entities with model translation methods for automatic conversions"""
1212

1313
@classmethod
14-
def from_model(cls, data: Any, /, *args: Any, **kwargs: Any) -> Self: ...
14+
def from_model(cls, data: Any, /, *args: Any, **kwargs: Any) -> Self:
15+
# Extra args to allow for entities with required fields not in the model
16+
...
1517

1618
def to_model(self) -> DtoModel: ...
1719

0 commit comments

Comments
 (0)