book-rec-with-LLMs / tests /test_api.py
ymlin105's picture
feat: integrate A/B testing framework and enhance RAG diversity in recommendation system
b4bfa19
"""
Integration tests for FastAPI endpoints.
Mocks src.main.recommender and rec_service so endpoints use fakes without loading models.
"""
from unittest.mock import patch, MagicMock, AsyncMock
import pytest
from fastapi.testclient import TestClient
from src.main import app
def _make_mock_recommender():
"""Create mock recommender with all endpoint needs."""
mock = MagicMock()
mock.get_recommendations = AsyncMock(return_value=[
{
"isbn": "123",
"title": "Test Book",
"authors": "Test Author",
"description": "A test book description",
"thumbnail": "test.jpg",
"caption": "Test Book by Test Author",
}
])
mock.get_categories.return_value = ["All", "Fiction"]
mock.get_tones.return_value = ["All", "Happy"]
mock.get_similar_books.return_value = []
mock.vector_db = MagicMock()
return mock
def _make_mock_rec_service():
"""Create mock rec_service for personalized endpoints."""
mock = MagicMock()
mock.get_recommendations.return_value = []
mock.get_popular_books.return_value = []
return mock
def test_health():
"""Health check returns 200 and healthy status."""
client = TestClient(app)
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "healthy"}
def test_recommend_mocked():
"""POST /recommend returns recommendations when recommender is mocked."""
mock_rec = _make_mock_recommender()
mock_svc = _make_mock_rec_service()
with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc):
client = TestClient(app)
response = client.post(
"/recommend",
json={"query": "a romantic comedy", "category": "All"},
)
assert response.status_code == 200
data = response.json()
assert "recommendations" in data
assert len(data["recommendations"]) > 0
assert data["recommendations"][0]["isbn"] == "123"
def test_categories_mocked():
"""GET /categories returns category list."""
mock_rec = _make_mock_recommender()
mock_svc = _make_mock_rec_service()
with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc):
client = TestClient(app)
response = client.get("/categories")
assert response.status_code == 200
assert "categories" in response.json()
assert "All" in response.json()["categories"]
def test_recommend_empty_query():
"""POST /recommend with empty query returns empty or error."""
mock_rec = _make_mock_recommender()
mock_rec.get_recommendations = AsyncMock(return_value=[])
mock_svc = _make_mock_rec_service()
with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc):
client = TestClient(app)
response = client.post(
"/recommend",
json={"query": "", "category": "All"},
)
assert response.status_code == 200
assert response.json()["recommendations"] == []
def test_similar_books_mocked():
"""GET /api/recommend/similar/{isbn} delegates to recommender."""
mock_rec = _make_mock_recommender()
mock_rec.get_similar_books.return_value = [
{"isbn": "456", "title": "Similar Book", "authors": "Author B", "description": "", "thumbnail": ""}
]
mock_svc = _make_mock_rec_service()
with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc):
client = TestClient(app)
response = client.get("/api/recommend/similar/123?k=5")
assert response.status_code == 200
assert response.json()["recommendations"][0]["isbn"] == "456"
def test_metrics_endpoint():
"""GET /metrics returns Prometheus format."""
client = TestClient(app)
response = client.get("/metrics")
assert response.status_code == 200
assert "http_requests_total" in response.text or "HELP" in response.text