Files
conference-room-booking-system/backend/tests/routers/test_users.py
2025-10-06 21:51:57 -04:00

121 lines
3.7 KiB
Python

"""Unit tests for the backend.routers.users module."""
from typing import Any
import pytest
import sqlalchemy.exc
from httpx import AsyncClient
from sqlalchemy.exc import SQLAlchemyError
from backend.dependencies.users import get_users_service
from backend.main import app
from backend.models import User
from backend.types import UserData
# Useful constants for users router tests
USERS_SUCCESS_STATUS = 200
USERS_DB_ERROR_STATUS = 500
USERS_NOT_FOUND_STATUS = 404
USERS_DB_ERROR_DETAIL = "Database error"
USERS_NOT_FOUND_DETAIL = "User not found"
USERS_UNEXPECTED_ERROR_DETAIL = "An unexpected error occurred"
@pytest.mark.asyncio
@pytest.mark.parametrize("has_users", [True, False], ids=["users_exist", "users_empty"])
async def test_read_users_parametrized(
client: AsyncClient,
sample_users: list[User],
sample_users_data: list[UserData],
has_users: bool,
) -> None:
"""Test GET /users/ for success and empty list cases.
Args:
client: The FastAPI test client for making HTTP requests.
sample_users: The list of sample User objects.
sample_users_data: The expected response data for users.
has_users: Whether to return users or an empty list.
Asserts:
- Response status code is USERS_SUCCESS_STATUS.
- Response JSON matches expected user data or empty list.
"""
async def mock_get_users(*args: Any, **kwargs: Any) -> list[User]:
return sample_users if has_users else []
app.dependency_overrides[get_users_service] = lambda: mock_get_users
response = await client.get("/users/")
assert response.status_code == USERS_SUCCESS_STATUS
expected = sample_users_data if has_users else []
assert response.json() == expected
@pytest.mark.asyncio
async def test_read_users_database_error(
client: AsyncClient,
) -> None:
"""Test GET /users/ for database error.
Args:
client: The FastAPI test client for making HTTP requests.
Asserts:
- Response status code is USERS_DB_ERROR_STATUS.
- Response JSON contains 'detail'.
"""
async def mock_get_users(*args: Any, **kwargs: Any) -> None:
raise SQLAlchemyError()
app.dependency_overrides[get_users_service] = lambda: mock_get_users
response = await client.get("/users/")
assert response.status_code == USERS_DB_ERROR_STATUS
assert "detail" in response.json()
# Parametrized error path tests for GET /users/
@pytest.mark.asyncio
@pytest.mark.parametrize(
"exception_to_raise,expected_status,expected_detail",
[
(
sqlalchemy.exc.NoResultFound(),
USERS_NOT_FOUND_STATUS,
USERS_NOT_FOUND_DETAIL,
),
(Exception("fail"), USERS_DB_ERROR_STATUS, USERS_UNEXPECTED_ERROR_DETAIL),
],
ids=["no_result_found", "unexpected_error"],
)
async def test_read_users_error_paths(
client: AsyncClient,
exception_to_raise: Exception,
expected_status: int,
expected_detail: str,
) -> None:
"""Test GET /users/ for error paths: NoResultFound (404) and generic exception (500).
Args:
client: The FastAPI test client for making HTTP requests.
exception_to_raise: The exception to raise in the service dependency.
expected_status: The expected HTTP status code.
expected_detail: The expected error detail message.
Asserts:
- Response status code matches expected_status.
- Response JSON 'detail' matches expected_detail.
"""
async def mock_get_users(*args: Any, **kwargs: Any) -> None:
raise exception_to_raise
app.dependency_overrides[get_users_service] = lambda: mock_get_users
response = await client.get("/users/")
assert response.status_code == expected_status
assert response.json()["detail"] == expected_detail