Spaces:
Sleeping
Sleeping
File size: 8,073 Bytes
532e8ec |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# tests/routes/test_patient_routes.py
from datetime import datetime, timezone
from unittest.mock import MagicMock
import pytest
from fastapi import FastAPI, status
from fastapi.testclient import TestClient
from src.api.routes.patient import router as patient_router
from src.core.state import get_state
from src.models.patient import Patient
from src.models.session import Session
# --- Test Setup: Mocking and Dependency Injection ---
# Mock the service layer that the API routes depend on.
mock_memory_manager = MagicMock()
# This mock AppState and override function will replace the real dependencies.
class MockAppState:
def __init__(self):
self.memory_manager = mock_memory_manager
def override_get_state() -> MockAppState:
return MockAppState()
# Create a FastAPI app instance for testing and apply the dependency override.
app = FastAPI()
app.include_router(patient_router)
app.dependency_overrides[get_state] = override_get_state
# --- Fixtures ---
@pytest.fixture
def client():
"""Provides a TestClient for making requests to the app."""
with TestClient(app) as c:
yield c
@pytest.fixture(autouse=True)
def reset_mocks():
"""Resets mocks before each test to ensure test isolation."""
mock_memory_manager.reset_mock()
# --- Test Data ---
fake_patient_dict = {
"_id": "patient123",
"name": "Jane Doe",
"age": 42,
"sex": "Female",
"ethnicity": "Caucasian",
"created_at": datetime.now(timezone.utc).isoformat(),
"updated_at": datetime.now(timezone.utc).isoformat(),
}
fake_patient = Patient.model_validate(fake_patient_dict)
fake_session_dict = {
"_id": "session456",
"account_id": "doctor789",
"patient_id": "patient123",
"title": "Checkup",
"created_at": datetime.now(timezone.utc).isoformat(),
"updated_at": datetime.now(timezone.utc).isoformat(),
"messages": [],
}
fake_session = Session.model_validate(fake_session_dict)
# --- Tests for GET /patient ---
def test_search_patients_success(client: TestClient):
"""Tests successfully searching for patients with a query."""
mock_memory_manager.search_patients.return_value = [fake_patient]
response = client.get("/patient?q=Jane&limit=5")
assert response.status_code == status.HTTP_200_OK
assert len(response.json()) == 1
assert response.json()[0]["name"] == "Jane Doe"
mock_memory_manager.search_patients.assert_called_once_with("Jane", limit=5)
def test_search_patients_requires_query(client: TestClient):
"""Tests that a 400 error is returned if the search query 'q' is missing."""
response = client.get("/patient")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["detail"] == "A search query 'q' is required."
# --- Tests for POST /patient ---
def test_create_patient_success(client: TestClient):
"""Tests successful creation of a new patient profile."""
new_patient_id = "new_patient_abc"
mock_memory_manager.create_patient.return_value = new_patient_id
mock_memory_manager.get_patient_by_id.return_value = fake_patient
patient_data = {"name": "Jane Doe", "age": 42, "sex": "Female", "ethnicity": "Caucasian"}
response = client.post("/patient", json=patient_data)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "Jane Doe"
mock_memory_manager.create_patient.assert_called_once()
mock_memory_manager.get_patient_by_id.assert_called_once_with(new_patient_id)
def test_create_patient_invalid_data(client: TestClient):
"""Tests failure when the memory manager cannot create a patient (e.g., bad data)."""
mock_memory_manager.create_patient.return_value = None
patient_data = {"name": "Invalid", "age": -5, "sex": "F", "ethnicity": "Unknown"}
response = client.post("/patient", json=patient_data)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["detail"] == "Patient could not be created due to invalid data."
def test_create_patient_not_found_after_creation(client: TestClient):
"""Tests the edge case where the patient can't be retrieved after creation."""
new_patient_id = "new_patient_abc"
mock_memory_manager.create_patient.return_value = new_patient_id
mock_memory_manager.get_patient_by_id.return_value = None
patient_data = {"name": "Jane Doe", "age": 42, "sex": "Female", "ethnicity": "Caucasian"}
response = client.post("/patient", json=patient_data)
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
assert response.json()["detail"] == "Could not find newly created patient."
# --- Tests for GET /patient/{patient_id} ---
def test_get_patient_by_id_success(client: TestClient):
"""Tests successfully retrieving a single patient by their ID."""
mock_memory_manager.get_patient_by_id.return_value = fake_patient
response = client.get(f"/patient/{fake_patient.id}")
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == fake_patient.name
mock_memory_manager.get_patient_by_id.assert_called_once_with(str(fake_patient.id))
def test_get_patient_by_id_not_found(client: TestClient):
"""Tests that a 404 error is returned for a non-existent patient ID."""
mock_memory_manager.get_patient_by_id.return_value = None
response = client.get("/patient/non_existent_id")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.json()["detail"] == "Patient not found"
# --- Tests for PATCH /patient/{patient_id} ---
def test_update_patient_success(client: TestClient):
"""Tests a successful patient profile update."""
mock_memory_manager.update_patient_profile.return_value = 1 # 1 document modified
mock_memory_manager.get_patient_by_id.return_value = fake_patient
update_data = {"age": 43}
response = client.patch(f"/patient/{fake_patient.id}", json=update_data)
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == fake_patient.name
mock_memory_manager.update_patient_profile.assert_called_once_with(str(fake_patient.id), update_data)
def test_update_patient_no_fields_provided(client: TestClient):
"""Tests that a 400 error is returned if the update request body is empty."""
response = client.patch(f"/patient/{fake_patient.id}", json={})
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["detail"] == "No update fields provided."
def test_update_patient_not_found(client: TestClient):
"""Tests updating a non-existent patient."""
mock_memory_manager.update_patient_profile.return_value = 0
# The route logic then checks if the patient exists. Simulate it not existing.
mock_memory_manager.get_patient_by_id.return_value = None
response = client.patch("/patient/non_existent_id", json={"age": 50})
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.json()["detail"] == "Patient not found"
# Check that get_patient_by_id was called as part of the 404 check
mock_memory_manager.get_patient_by_id.assert_called_once_with("non_existent_id")
# --- Tests for GET /patient/{patient_id}/session ---
def test_list_sessions_for_patient_success(client: TestClient):
"""Tests successfully listing all sessions for a given patient."""
mock_memory_manager.get_patient_by_id.return_value = fake_patient
mock_memory_manager.list_patient_sessions.return_value = [fake_session]
response = client.get(f"/patient/{fake_patient.id}/session")
assert response.status_code == status.HTTP_200_OK
assert len(response.json()) == 1
assert response.json()[0]["title"] == "Checkup"
# Verify it first checked that the patient exists
mock_memory_manager.get_patient_by_id.assert_called_once_with(str(fake_patient.id))
mock_memory_manager.list_patient_sessions.assert_called_once_with(str(fake_patient.id))
def test_list_sessions_for_patient_not_found(client: TestClient):
"""Tests listing sessions for a non-existent patient."""
mock_memory_manager.get_patient_by_id.return_value = None
response = client.get("/patient/non_existent_id/session")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.json()["detail"] == "Patient not found"
mock_memory_manager.list_patient_sessions.assert_not_called()
|