Files
conference-room-booking-system/backend/tests/services/test_users.py
T

180 lines
6.0 KiB
Python
Raw Normal View History

2025-08-24 15:13:14 -04:00
"""Unit tests for the backend.services.users module."""
from unittest.mock import AsyncMock
from unittest.mock import MagicMock
import pytest
from sqlalchemy import select
from sqlalchemy.exc import NoResultFound
from sqlalchemy.exc import SQLAlchemyError
2025-08-24 15:13:14 -04:00
from sqlalchemy.ext.asyncio import AsyncSession
from backend.models import User
2025-08-26 17:15:56 -04:00
from backend.models import UserList
2025-08-24 15:13:14 -04:00
from backend.services.users import get_user
from backend.services.users import get_users
@pytest.mark.asyncio
2025-08-25 21:38:31 -04:00
@pytest.mark.parametrize("mock_logger", ["backend.services.users"], indirect=True)
2025-08-24 15:13:14 -04:00
async def test_get_users_success(
2025-08-25 21:38:31 -04:00
async_session: AsyncSession, sample_users: UserList, mock_logger: MagicMock
2025-08-24 15:13:14 -04:00
) -> None:
"""Test successful retrieval of all users from the database.
2025-08-26 15:47:08 -04:00
Args:
async_session: The asynchronous database session.
2025-09-22 11:54:03 -04:00
sample_users: The list of sample user objects to return.
2025-08-26 15:47:08 -04:00
mock_logger: The mocked logger instance.
2025-08-24 15:13:14 -04:00
"""
mock_scalars_result = AsyncMock()
mock_scalars_result.all = MagicMock(return_value=sample_users)
2025-08-24 15:13:14 -04:00
mock_scalars = AsyncMock(return_value=mock_scalars_result)
2025-08-26 09:45:41 -04:00
async_session.scalars = mock_scalars # type: ignore [method-assign]
2025-08-24 15:13:14 -04:00
result: UserList = await get_users(async_session)
assert isinstance(result, list)
assert len(result) == 2
assert result == sample_users
async_session.scalars.assert_called_once()
assert async_session.scalars.call_args.args[0].compare(select(User))
@pytest.mark.asyncio
2025-08-25 21:38:31 -04:00
@pytest.mark.parametrize("mock_logger", ["backend.services.users"], indirect=True)
async def test_get_users_empty(
2025-08-25 21:38:31 -04:00
async_session: AsyncSession, mock_logger: MagicMock
) -> None:
2025-08-24 15:13:14 -04:00
"""Test retrieval of users when the database is empty.
2025-08-26 15:47:08 -04:00
Args:
async_session: The asynchronous database session.
mock_logger: The mocked logger instance.
2025-08-24 15:13:14 -04:00
"""
mock_scalars_result = AsyncMock()
mock_scalars_result.all = MagicMock(return_value=[])
2025-08-24 15:13:14 -04:00
mock_scalars = AsyncMock(return_value=mock_scalars_result)
2025-08-26 09:45:41 -04:00
async_session.scalars = mock_scalars # type: ignore [method-assign]
2025-08-24 15:13:14 -04:00
result: UserList = await get_users(async_session)
assert isinstance(result, list)
assert len(result) == 0
async_session.scalars.assert_called_once()
assert async_session.scalars.call_args.args[0].compare(select(User))
@pytest.mark.asyncio
2025-08-25 21:38:31 -04:00
@pytest.mark.parametrize("mock_logger", ["backend.services.users"], indirect=True)
2025-08-24 15:13:14 -04:00
async def test_get_users_database_error(
2025-08-25 21:38:31 -04:00
async_session: AsyncSession, mock_logger: MagicMock
2025-08-24 15:13:14 -04:00
) -> None:
"""Test handling of database errors in get_users.
2025-08-26 15:47:08 -04:00
Verifies that get_users raises an exception on database failure.
Args:
async_session: The asynchronous database session.
mock_logger: The mocked logger instance.
2025-08-24 15:13:14 -04:00
"""
2025-08-26 09:45:41 -04:00
async_session.scalars = AsyncMock( # type: ignore [method-assign]
side_effect=SQLAlchemyError("Database error")
)
2025-08-24 15:13:14 -04:00
with pytest.raises(SQLAlchemyError):
2025-08-24 15:13:14 -04:00
await get_users(async_session)
async_session.scalars.assert_called_once()
@pytest.mark.asyncio
2025-08-25 21:38:31 -04:00
@pytest.mark.parametrize("mock_logger", ["backend.services.users"], indirect=True)
2025-08-24 15:13:14 -04:00
@pytest.mark.parametrize(
"email, expected_name",
[
("user1@example.com", "User One"),
("user2@example.com", "User Two"),
],
ids=["user1", "user2"],
)
async def test_get_user_success(
2025-08-25 21:38:31 -04:00
async_session: AsyncSession, email: str, expected_name: str, mock_logger: MagicMock
2025-08-24 15:13:14 -04:00
) -> None:
"""Test successful retrieval of a user by email.
Verifies that get_user returns the correct user and constructs the correct query.
2025-08-26 15:47:08 -04:00
Args:
async_session: The asynchronous database session.
email: The email of the user to retrieve.
expected_name: The expected name of the user.
mock_logger: The mocked logger instance.
2025-08-24 15:13:14 -04:00
"""
user = User(email=email, name=expected_name)
2025-08-26 09:45:41 -04:00
async_session.scalar = AsyncMock(return_value=user) # type: ignore [method-assign]
2025-08-24 15:13:14 -04:00
result: User = await get_user(async_session, email)
assert result.email == email
assert result.name == expected_name
async_session.scalar.assert_called_once()
assert async_session.scalar.call_args.args[0].compare(
select(User).where(User.email == email)
)
@pytest.mark.asyncio
2025-08-25 21:38:31 -04:00
@pytest.mark.parametrize("mock_logger", ["backend.services.users"], indirect=True)
2025-08-24 15:13:14 -04:00
@pytest.mark.parametrize(
"email",
[
"nonexistent@example.com",
"invalid@domain.com",
],
ids=["nonexistent_email", "invalid_email"],
)
async def test_get_user_not_found(
2025-08-25 21:38:31 -04:00
async_session: AsyncSession, mock_logger: MagicMock, email: str
2025-08-24 15:13:14 -04:00
) -> None:
"""Test handling of non-existent user in get_user.
2025-08-26 15:47:08 -04:00
Verifies that get_user raises NoResultFound when the user is not found.
Args:
async_session: The asynchronous database session.
mock_logger: The mocked logger instance.
email: The email of the user to retrieve.
2025-08-24 15:13:14 -04:00
"""
2025-08-26 09:45:41 -04:00
async_session.scalar = AsyncMock(return_value=None) # type: ignore [method-assign]
2025-08-24 15:13:14 -04:00
with pytest.raises(NoResultFound):
2025-08-24 15:13:14 -04:00
await get_user(async_session, email)
async_session.scalar.assert_called_once()
assert async_session.scalar.call_args.args[0].compare(
select(User).where(User.email == email)
)
@pytest.mark.asyncio
2025-08-25 21:38:31 -04:00
@pytest.mark.parametrize("mock_logger", ["backend.services.users"], indirect=True)
2025-08-24 15:13:14 -04:00
async def test_get_user_database_error(
2025-08-25 21:38:31 -04:00
async_session: AsyncSession, mock_logger: MagicMock
2025-08-24 15:13:14 -04:00
) -> None:
2025-09-22 11:54:03 -04:00
"""Test handling of database errors in get_users.
2025-08-26 15:47:08 -04:00
Args:
async_session: The asynchronous database session.
mock_logger: The mocked logger instance.
2025-08-24 15:13:14 -04:00
"""
email: str = "user1@example.com"
2025-08-26 09:45:41 -04:00
async_session.scalar = AsyncMock( # type: ignore [method-assign]
side_effect=SQLAlchemyError("Database error")
)
2025-08-24 15:13:14 -04:00
with pytest.raises(SQLAlchemyError):
2025-08-24 15:13:14 -04:00
await get_user(async_session, email)
async_session.scalar.assert_called_once()
assert async_session.scalar.call_args.args[0].compare(
select(User).where(User.email == email)
)