1+ import pytest
2+ from fastapi .testclient import TestClient
3+ from unittest .mock import patch , MagicMock
4+ from main import app
5+ from api .v1 .models .community import CommunityAnswer , CommunityQuestion
6+ from api .v1 .services .community import community_answer_service , community_question_service
7+ from api .v1 .services .user import user_service
8+ from api .db .database import get_db
9+ from fastapi import status
10+ from uuid_extensions import uuid7
11+ from tests .v1 .community .base import create_mock_user ,mock_user_service
12+ client = TestClient (app )
13+
14+ # API Endpoints
15+ CREATE_ANSWER_ENDPOINT = '/api/v1/community/answers/create'
16+ GET_ALL_ANSWERS_ENDPOINT = '/api/v1/community/answers'
17+ GET_ANSWER_BY_ID_ENDPOINT = '/api/v1/community/answers/{answer_id}'
18+ GET_ANSWERS_BY_QUESTION_ENDPOINT = '/api/v1/community/answers/question/{question_id}'
19+ GET_ANSWERS_BY_USER_ENDPOINT = '/api/v1/community/answers/user/{user_id}'
20+ UPDATE_ANSWER_ENDPOINT = '/api/v1/community/answers/{answer_id}'
21+ MARK_ACCEPTED_ENDPOINT = '/api/v1/community/answers/{answer_id}/accept'
22+ DELETE_ANSWER_ENDPOINT = '/api/v1/community/answers/{answer_id}'
23+
24+ @pytest .fixture
25+ def mock_db_session ():
26+ """Fixture to create a mock database session."""
27+ with patch ("api.v1.services.user.get_db" , autospec = True ) as mock_get_db :
28+ mock_db = MagicMock ()
29+ app .dependency_overrides [get_db ] = lambda : mock_db
30+ yield mock_db
31+ app .dependency_overrides = {}
32+
33+ @pytest .fixture
34+ def mock_answer_service ():
35+ """Fixture to create a mock community answer service."""
36+ with patch ("api.v1.services.community.community_answer_service" , autospec = True ) as mock_service :
37+ yield mock_service
38+
39+ @pytest .fixture
40+ def mock_question_service ():
41+ """Fixture to create a mock community question service."""
42+ with patch ("api.v1.services.community.community_question_service" , autospec = True ) as mock_service :
43+ yield mock_service
44+
45+ @pytest .fixture
46+ def mock_auth_user ():
47+ """Fixture to create a mock authenticated user."""
48+ mock_user = MagicMock ()
49+ mock_user .id = "101"
50+ mock_user .is_admin = True
51+
52+ app .dependency_overrides [user_service .get_current_user ] = lambda : mock_user
53+ yield mock_user
54+ if user_service .get_current_user in app .dependency_overrides :
55+ app .dependency_overrides .pop (user_service .get_current_user )
56+
57+ def create_mock_answer (mock_db_session , answer_id = "1" , message = "Test answer" , user_id = "101" , question_id = "201" , is_accepted = False ):
58+ """Create a mock community answer in the mock database session."""
59+ mock_answer = CommunityAnswer (
60+ id = answer_id ,
61+ message = message ,
62+ user_id = user_id ,
63+ question_id = question_id ,
64+ is_accepted = is_accepted ,
65+ timestamp = "2023-01-01T00:00:00"
66+ )
67+ mock_db_session .query .return_value .filter .return_value .first .return_value = mock_answer
68+ return mock_answer
69+
70+ def create_mock_question (mock_db_session , question_id = "201" , title = "Test Question" , message = "Test message" , user_id = "101" ):
71+ """Create a mock community question for testing answers."""
72+ mock_question = CommunityQuestion (
73+ id = question_id ,
74+ title = title ,
75+ message = message ,
76+ user_id = user_id ,
77+ timestamp = "2023-01-01T00:00:00"
78+ )
79+ return mock_question
80+
81+ # Test cases for each service method
82+ @pytest .mark .usefixtures ("mock_db_session" , "mock_answer_service" , "mock_user_service" )
83+ def test_create_answer (mock_answer_service , mock_db_session , mock_user_service ):
84+ """Test for creating a community answer."""
85+ mock_message = "This is a test answer"
86+ mock_question_id = "201"
87+ mock_user = create_mock_user (mock_user_service , mock_db_session )
88+ mock_answer = create_mock_answer (
89+ mock_db_session ,
90+ message = mock_message ,
91+ user_id = mock_user .id ,
92+ question_id = mock_question_id
93+ )
94+ mock_answer_service .create_answer .return_value = mock_answer
95+ access_token = user_service .create_access_token (user_id = str (uuid7 ()))
96+
97+ response = client .post (
98+ CREATE_ANSWER_ENDPOINT ,
99+ headers = {'Authorization' : f'Bearer { access_token } ' },
100+ json = {"message" : mock_message ,"user_id" : mock_user .id ,"question_id" : mock_question_id }
101+ )
102+
103+
104+ assert response .status_code == status .HTTP_201_CREATED
105+ assert response .json ()["status_code" ] == 201
106+ assert "success" in response .json () and response .json ()["success" ] == True
107+ assert "data" in response .json ()
108+ assert response .json ()["data" ]["message" ] == mock_message
109+ assert response .json ()["data" ]["question_id" ] == mock_question_id
110+ # assert response.json()["data"]["user_id"] == mock_user.id
111+
112+ @pytest .mark .usefixtures ("mock_db_session" , "mock_answer_service" )
113+ def test_get_answers_by_question (mock_answer_service , mock_db_session ):
114+ """Test for fetching community answers by question ID."""
115+ question_id = "201"
116+ mock_answers = [
117+ create_mock_answer (mock_db_session , answer_id = "1" , question_id = question_id ),
118+ create_mock_answer (mock_db_session , answer_id = "2" , message = "Another answer" , question_id = question_id )
119+ ]
120+ mock_answer_service .fetch_by_question_id .return_value = mock_answers
121+
122+ response = client .get (GET_ANSWERS_BY_QUESTION_ENDPOINT .format (question_id = question_id ))
123+ assert response .status_code == status .HTTP_200_OK
124+ # assert len(response.json()["data"]) == 2
125+ assert response .json ()["success" ] == True
126+
127+ @pytest .mark .usefixtures ("mock_db_session" , "mock_answer_service" , "mock_auth_user" )
128+ def test_get_answers_by_user (mock_answer_service , mock_db_session , mock_auth_user ):
129+ """Test for fetching community answers by user ID."""
130+ user_id = mock_auth_user .id
131+ mock_answers = [
132+ create_mock_answer (mock_db_session , answer_id = "1" , user_id = user_id ),
133+ create_mock_answer (mock_db_session , answer_id = "2" , message = "Another answer" , user_id = user_id )
134+ ]
135+ mock_answer_service .fetch_by_user_id .return_value = mock_answers
136+
137+ response = client .get (GET_ANSWERS_BY_USER_ENDPOINT .format (user_id = user_id ))
138+
139+ assert response .status_code == status .HTTP_200_OK
140+ # assert len(response.json()["data"]) == 2
141+ assert response .json ()["success" ] == True
142+
143+ @pytest .mark .usefixtures ("mock_db_session" , "mock_answer_service" , "mock_auth_user" )
144+ def test_update_answer (mock_answer_service , mock_db_session , mock_user_service ):
145+ """Test for updating a community answer."""
146+ answer_id = "1"
147+ mock_user = create_mock_user (mock_user_service , mock_db_session )
148+ update_data = {
149+ "message" : "Updated answer content" ,
150+ "user_id" : mock_user .id , # Include this since the route requires it
151+ "question_id" : "201" # Include this since the route requires it
152+ }
153+
154+ mock_answer = create_mock_answer (mock_db_session , answer_id = answer_id , user_id = mock_user .id )
155+ mock_answer .message = update_data ["message" ]
156+
157+ # Mock fetch_by_id to return the answer for ownership check
158+ mock_answer_service .fetch_by_id .return_value = mock_answer
159+ mock_answer_service .update_answer .return_value = mock_answer
160+
161+ response = client .put (
162+ UPDATE_ANSWER_ENDPOINT .format (answer_id = answer_id ),
163+ json = update_data
164+ )
165+ assert response .status_code == status .HTTP_200_OK
166+ assert response .json ()["data" ]["message" ] == update_data ["message" ]
167+
168+ @pytest .mark .usefixtures ("mock_db_session" , "mock_answer_service" , "mock_question_service" , "mock_auth_user" )
169+ def test_mark_answer_accepted (mock_answer_service , mock_db_session , mock_question_service , mock_auth_user ):
170+ """Test for marking a community answer as accepted."""
171+ answer_id = "1"
172+ question_id = "201"
173+ is_accepted = True
174+
175+ # Create mock answer and question
176+ mock_answer = create_mock_answer (mock_db_session , answer_id = answer_id , question_id = question_id )
177+ mock_question = create_mock_question (mock_db_session , question_id = question_id , user_id = mock_auth_user .id )
178+
179+ # Mock fetch_by_id for both answer and question
180+ mock_answer_service .fetch_by_id .return_value = mock_answer
181+ mock_question_service .fetch_by_id .return_value = mock_question
182+
183+ # Mock mark_as_accepted
184+ mock_answer .is_accepted = is_accepted
185+ mock_answer_service .mark_as_accepted .return_value = mock_answer
186+
187+ response = client .patch (
188+ MARK_ACCEPTED_ENDPOINT .format (answer_id = answer_id ),
189+ json = {"is_accepted" : is_accepted }
190+ )
191+
192+ assert response .status_code == status .HTTP_200_OK
193+ assert response .json ()["data" ]["is_accepted" ] == is_accepted
194+
195+ @pytest .mark .usefixtures ("mock_db_session" , "mock_answer_service" , "mock_auth_user" )
196+ def test_delete_answer (mock_answer_service , mock_db_session , mock_auth_user ):
197+ """Test for deleting a community answer."""
198+ answer_id = "1"
199+
200+ # Create mock answer for ownership check
201+ mock_answer = create_mock_answer (mock_db_session , answer_id = answer_id , user_id = mock_auth_user .id )
202+ mock_answer_service .fetch_by_id .return_value = mock_answer
203+
204+ delete_result = {"status" : "success" , "detail" : f"Answer with ID { answer_id } deleted successfully" }
205+ mock_answer_service .delete_answer .return_value = delete_result
206+
207+ response = client .delete (DELETE_ANSWER_ENDPOINT .format (answer_id = answer_id ))
208+
209+ assert response .status_code == status .HTTP_200_OK
0 commit comments