Empty package marker.
Shared pytest fixtures:
mock_rag_system—MagicMockpre-wired withquery(),get_course_analytics(), andsession_manager.create_session()return valuestest_app— inlineFastAPIapp that mirrors the routes fromapp.pywithout static file mounting or ChromaDB initialisation; closes overmock_rag_systemso per-test mutations are reflectedclient—TestClientwrappingtest_app
13 API endpoint tests across two classes:
TestQueryEndpoint
test_returns_answer_and_sources— happy path response shapetest_uses_provided_session_id— session_id passed through to RAG and returnedtest_creates_session_when_none_provided— session created automatically when omittedtest_returns_empty_sources_list— empty sources list handled correctlytest_missing_required_query_field_returns_422— validation error on missingquerytest_empty_body_returns_422— validation error on empty bodytest_rag_error_returns_500— RAG exception surfaces as 500 with detail messagetest_response_has_all_required_fields— all three fields present in response
TestCoursesEndpoint
test_returns_course_list— correct count and titlestest_total_courses_matches_titles_length— count is consistent with list lengthtest_response_has_all_required_fields— both fields presenttest_empty_course_list— zero courses handled correctlytest_rag_error_returns_500— RAG exception surfaces as 500 with detail message
Added pytest configuration and dev dependencies:
[dependency-groups]
dev = [
"pytest>=8.0",
"httpx>=0.27",
]
[tool.pytest.ini_options]
testpaths = ["backend/tests"]
pythonpath = ["backend"]app.py initialises RAGSystem at module level and mounts StaticFiles from ../frontend, both of which fail in a test environment (no ChromaDB, no frontend build). The test app in conftest.py defines the same endpoint logic inline with a mocked RAGSystem, avoiding the import entirely. Tests that need to change mock behaviour (error cases) receive both client and mock_rag_system as fixtures — pytest gives them the same object instance within a test, so side_effect mutations work correctly.