Files
conference-room-booking-system/backend/tests/routers/test_rooms.py
2025-08-27 15:51:05 -04:00

278 lines
9.2 KiB
Python

"""Tests for backend.routers.rooms in the Numinar coding project backend."""
from typing import Any
from unittest.mock import ANY
from unittest.mock import AsyncMock
from unittest.mock import MagicMock
from unittest.mock import patch
import pytest
from httpx import AsyncClient
from sqlalchemy.exc import NoResultFound
from backend.models import Room
from backend.models import RoomList
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_get_rooms_success(
client: AsyncClient, sample_rooms: RoomList, mock_logger: MagicMock
) -> None:
"""Test successful retrieval of all rooms via GET /rooms/.
Verifies that the endpoint returns the expected list of rooms with a 200 status.
Args:
client: The FastAPI test client for making HTTP requests.
sample_rooms: The mocked list of rooms to return.
mock_logger: The mocked logger instance.
"""
with patch("backend.routers.rooms.get_rooms", new=AsyncMock()) as mock_get_rooms:
mock_get_rooms.return_value = sample_rooms
response = await client.get("/rooms/")
assert response.status_code == 200
assert response.json() == [
{
"id": 1,
"name": "Room 1",
"location": "Building A",
"equipment": "Projector",
"capacity": 10,
},
{
"id": 2,
"name": "Room 2",
"location": "Building B",
"equipment": "Whiteboard",
"capacity": 15,
},
]
mock_get_rooms.assert_called_once()
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_get_rooms_empty(client: AsyncClient, mock_logger: MagicMock) -> None:
"""Test retrieval of rooms when none exist via GET /rooms/.
Verifies that the endpoint returns an empty list with a 200 status.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
with patch("backend.routers.rooms.get_rooms", new=AsyncMock()) as mock_get_rooms:
mock_get_rooms.return_value = []
response = await client.get("/rooms/")
assert response.status_code == 200
assert response.json() == []
mock_get_rooms.assert_called_once()
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_get_room_success(client: AsyncClient, mock_logger: MagicMock) -> None:
"""Test successful retrieval of a room by ID via GET /rooms/{room_id}.
Verifies that the endpoint returns the correct room with a 200 status.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_id = 1
room = Room(
id=room_id,
name="Room 1",
location="Building A",
equipment="Projector",
capacity=10,
)
with patch("backend.routers.rooms.get_room", new=AsyncMock()) as mock_get_room:
mock_get_room.return_value = room
response = await client.get(f"/rooms/{room_id}")
assert response.status_code == 200
assert response.json() == {
"id": room_id,
"name": "Room 1",
"location": "Building A",
"equipment": "Projector",
"capacity": 10,
}
mock_get_room.assert_called_once_with(ANY, room_id)
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_get_room_not_found(client: AsyncClient, mock_logger: MagicMock) -> None:
"""Test handling of non-existent room in GET /rooms/{room_id}.
Verifies that the endpoint returns a 404 status when the room is not found.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_id = 999
with patch("backend.routers.rooms.get_room", new=AsyncMock()) as mock_get_room:
mock_get_room.side_effect = NoResultFound(f"Room with id {room_id} not found")
response = await client.get(f"/rooms/{room_id}")
assert response.status_code == 404
assert "detail" in response.json()
mock_get_room.assert_called_once_with(ANY, room_id)
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_new_room_success(client: AsyncClient, mock_logger: MagicMock) -> None:
"""Test successful creation of a new room via POST /rooms/.
Verifies that the endpoint returns the created room with a 201 status.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_data: dict[str, Any] = {
"id": 3,
"name": "Room 3",
"location": "Building C",
"equipment": "TV",
"capacity": 20,
}
created_room = Room(**room_data)
with patch("backend.routers.rooms.new_room", new=AsyncMock()) as mock_new_room:
mock_new_room.return_value = created_room
response = await client.post("/rooms/", json=room_data)
assert response.status_code == 201
assert response.json() == room_data
mock_new_room.assert_called_once()
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_update_room_success(client: AsyncClient, mock_logger: MagicMock) -> None:
"""Test successful update of a room via PUT /rooms/{room_id}.
Verifies that the endpoint returns the updated room with a 200 status.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_id = 1
update_data: dict[str, Any] = {
"name": "Updated Room",
"location": "Building D",
"equipment": "Monitor",
"capacity": 25,
}
updated_room = Room(id=room_id, **update_data)
with patch(
"backend.routers.rooms.update_room", new=AsyncMock()
) as mock_update_room:
mock_update_room.return_value = updated_room
response = await client.put(f"/rooms/{room_id}", json=update_data)
assert response.status_code == 200
assert response.json() == {
"id": room_id,
"name": "Updated Room",
"location": "Building D",
"equipment": "Monitor",
"capacity": 25,
}
mock_update_room.assert_called_once_with(ANY, room_id, **update_data)
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_update_room_not_found(
client: AsyncClient, mock_logger: MagicMock
) -> None:
"""Test handling of non-existent room in PUT /rooms/{room_id}.
Verifies that the endpoint returns a 404 status when the room is not found.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_id = 999
update_data: dict[str, Any] = {
"name": "Updated Room",
"location": "Building D",
"equipment": "Monitor",
"capacity": 25,
}
with patch(
"backend.routers.rooms.update_room", new=AsyncMock()
) as mock_update_room:
mock_update_room.side_effect = ValueError()
response = await client.put(f"/rooms/{room_id}", json=update_data)
assert response.status_code == 404
assert "detail" in response.json()
mock_update_room.assert_called_once_with(ANY, room_id, **update_data)
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_delete_room_success(client: AsyncClient, mock_logger: MagicMock) -> None:
"""Test successful deletion of a room via DELETE /rooms/{room_id}.
Verifies that the endpoint returns a 204 status on successful deletion.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_id = 1
with patch(
"backend.routers.rooms.delete_room", new=AsyncMock()
) as mock_delete_room:
response = await client.delete(f"/rooms/{room_id}")
assert response.status_code == 204
assert response.text == ""
mock_delete_room.assert_called_once_with(ANY, room_id)
@pytest.mark.asyncio
@pytest.mark.parametrize("mock_logger", ["backend.routers.rooms"], indirect=True)
async def test_delete_room_not_found(
client: AsyncClient, mock_logger: MagicMock
) -> None:
"""Test handling of non-existent room in DELETE /rooms/{room_id}.
Verifies that the endpoint returns a 404 status when the room is not found.
Args:
client: The FastAPI test client for making HTTP requests.
mock_logger: The mocked logger instance.
"""
room_id = 999
with patch(
"backend.routers.rooms.delete_room", new=AsyncMock()
) as mock_delete_room:
mock_delete_room.side_effect = ValueError()
response = await client.delete(f"/rooms/{room_id}")
assert response.status_code == 404
assert "detail" in response.json()
mock_delete_room.assert_called_once_with(ANY, room_id)