Added unit tests for user api
This commit is contained in:
@@ -79,7 +79,7 @@ def get_current_user(
|
||||
return user
|
||||
|
||||
|
||||
def get_admin_user(current_user: UserInDB = Depends(get_current_user)) -> UserInDB:
|
||||
def get_admin_user(current_user: UserInDB = Depends(get_current_user)) -> UserInDB:
|
||||
"""
|
||||
Dependency to ensure current user has admin role.
|
||||
|
||||
|
||||
167
tests/api/test_users.py
Normal file
167
tests/api/test_users.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# File: tests/api/test_users.py
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from fastapi import status
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.api.dependencies import get_admin_user, get_user_service
|
||||
from app.main import app
|
||||
from app.models.auth import UserRole
|
||||
from app.models.types import PyObjectId
|
||||
from app.models.user import UserInDB, UserCreate
|
||||
from app.services.user_service import UserService
|
||||
|
||||
|
||||
# -----------------------
|
||||
# Fixtures
|
||||
# -----------------------
|
||||
|
||||
@pytest.fixture
|
||||
def fake_user_admin():
|
||||
return UserInDB(
|
||||
_id=PyObjectId(),
|
||||
username="admin",
|
||||
email="admin@example.com",
|
||||
role=UserRole.ADMIN,
|
||||
is_active=True,
|
||||
hashed_password="hashed-secret",
|
||||
created_at=datetime(2025, 1, 1),
|
||||
updated_at=datetime(2025, 1, 2),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_user_response():
|
||||
return UserInDB(
|
||||
_id=PyObjectId(),
|
||||
username="other",
|
||||
email="other@example.com",
|
||||
role=UserRole.USER,
|
||||
is_active=True,
|
||||
hashed_password="hashed-secret-2",
|
||||
created_at=datetime(2025, 1, 1),
|
||||
updated_at=datetime(2025, 1, 2),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(fake_user_admin):
|
||||
# Fake admin dependency
|
||||
def get_admin_user_override():
|
||||
return fake_user_admin
|
||||
|
||||
# Fake user service
|
||||
user_service_mock = MagicMock(spec=UserService)
|
||||
|
||||
def get_user_service_override():
|
||||
return user_service_mock
|
||||
|
||||
client = TestClient(app)
|
||||
client.app.dependency_overrides = {
|
||||
get_admin_user: get_admin_user_override,
|
||||
get_user_service: get_user_service_override
|
||||
}
|
||||
|
||||
client.user_service_mock = user_service_mock
|
||||
return client
|
||||
|
||||
|
||||
# -----------------------
|
||||
# Tests
|
||||
# -----------------------
|
||||
|
||||
class TestListUsers:
|
||||
|
||||
def test_i_can_list_users(self, client, fake_user_admin, fake_user_response):
|
||||
client.user_service_mock.list_users.return_value = [fake_user_admin, fake_user_response]
|
||||
response = client.get("/users")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert len(data) == 2
|
||||
assert data[0]["username"] == "admin"
|
||||
|
||||
def test_i_can_list_users_when_empty(self, client):
|
||||
client.user_service_mock.list_users.return_value = []
|
||||
response = client.get("/users")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == []
|
||||
|
||||
|
||||
class TestGetUserById:
|
||||
|
||||
def test_i_can_get_user_by_id(self, client, fake_user_response):
|
||||
client.user_service_mock.get_user_by_id.return_value = fake_user_response
|
||||
response = client.get(f"/users/{fake_user_response.id}")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert data["username"] == fake_user_response.username
|
||||
|
||||
def test_i_cannot_get_user_by_id_not_found(self, client):
|
||||
client.user_service_mock.get_user_by_id.return_value = None
|
||||
response = client.get("/users/64f0c9f4b0d1c8b7b8e1f0a2")
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
assert response.json()["detail"] == "User not found"
|
||||
|
||||
|
||||
class TestCreateUser:
|
||||
|
||||
def test_i_can_create_user(self, client, fake_user_response):
|
||||
user_data = UserCreate(username="newuser",
|
||||
email="new@example.com",
|
||||
password="#Passw0rd!",
|
||||
role=UserRole.USER)
|
||||
|
||||
client.user_service_mock.create_user.return_value = fake_user_response
|
||||
response = client.post("/users", json=user_data.model_dump(mode="json"))
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
data = response.json()
|
||||
assert data["username"] == fake_user_response.username
|
||||
|
||||
def test_i_cannot_create_user_when_service_raises_value_error(self, client):
|
||||
user_data = {"username": "baduser", "email": "bad@example.com", "role": "user", "password": "password"}
|
||||
client.user_service_mock.create_user.side_effect = ValueError("Invalid data")
|
||||
response = client.post("/users", json=user_data)
|
||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
|
||||
|
||||
class TestUpdateUser:
|
||||
|
||||
def test_i_can_update_user(self, client, fake_user_response):
|
||||
user_data = {"username": "updateduser", "email": "updated@example.com"}
|
||||
client.user_service_mock.update_user.return_value = fake_user_response
|
||||
response = client.put(f"/users/{fake_user_response.id}", json=user_data)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert data["username"] == fake_user_response.username
|
||||
|
||||
def test_i_cannot_update_user_not_found(self, client):
|
||||
client.user_service_mock.update_user.return_value = None
|
||||
user_data = {"username": "updateduser"}
|
||||
response = client.put("/users/64f0c9f4b0d1c8b7b8e1f0a2", json=user_data)
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
assert response.json()["detail"] == "User not found"
|
||||
|
||||
def test_i_cannot_update_user_when_service_raises_value_error(self, client):
|
||||
client.user_service_mock.update_user.side_effect = ValueError("Invalid update")
|
||||
user_data = {"username": "badupdate"}
|
||||
response = client.put("/users/64f0c9f4b0d1c8b7b8e1f0a2", json=user_data)
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert response.json()["detail"] == "Invalid update"
|
||||
|
||||
|
||||
class TestDeleteUser:
|
||||
|
||||
def test_i_can_delete_user(self, client):
|
||||
client.user_service_mock.delete_user.return_value = True
|
||||
response = client.delete("/users/64f0c9f4b0d1c8b7b8e1f0a1")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert data["message"] == "User successfully deleted"
|
||||
|
||||
def test_i_cannot_delete_user_not_found(self, client):
|
||||
client.user_service_mock.delete_user.return_value = False
|
||||
response = client.delete("/users/64f0c9f4b0d1c8b7b8e1f0a2")
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
assert response.json()["detail"] == "User not found"
|
||||
Reference in New Issue
Block a user