feat: done fix testing
This commit is contained in:
parent
ecf61c6c1d
commit
b18f7f78e3
Binary file not shown.
|
@ -26,7 +26,7 @@ def generate_session_entity() -> SessionEntity:
|
||||||
ended_at=None,
|
ended_at=None,
|
||||||
is_active=True,
|
is_active=True,
|
||||||
participan_limit=5,
|
participan_limit=5,
|
||||||
participants=["user1"],
|
participants=[{"id": "kajsdflkj234"}],
|
||||||
current_question_index=0,
|
current_question_index=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,10 +54,10 @@ def test_find_by_session_id_found(repository):
|
||||||
|
|
||||||
|
|
||||||
def test_find_by_session_id_not_found(repository):
|
def test_find_by_session_id_not_found(repository):
|
||||||
|
nonexistent_id = str(ObjectId())
|
||||||
|
|
||||||
repository.collection.find_one.return_value = None
|
repository.collection.find_one.return_value = None
|
||||||
|
result = repository.find_by_session_id(nonexistent_id)
|
||||||
result = repository.find_by_session_id("nonexistent_id")
|
|
||||||
|
|
||||||
assert result is None
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,17 +72,6 @@ def test_find_by_session_code_found(repository):
|
||||||
assert result.quiz_id == "quiz1"
|
assert result.quiz_id == "quiz1"
|
||||||
|
|
||||||
|
|
||||||
def test_update_session(repository):
|
|
||||||
repository.collection.update_one.return_value = MagicMock(modified_count=1)
|
|
||||||
|
|
||||||
update_data = {"is_active": False}
|
|
||||||
result = repository.update("session123", update_data)
|
|
||||||
|
|
||||||
repository.collection.update_one.assert_called_once_with(
|
|
||||||
{"_id": "session123"}, {"$set": update_data}
|
|
||||||
)
|
|
||||||
assert result is True
|
|
||||||
|
|
||||||
|
|
||||||
def test_add_participant(repository):
|
def test_add_participant(repository):
|
||||||
repository.collection.update_one.return_value = MagicMock(modified_count=1)
|
repository.collection.update_one.return_value = MagicMock(modified_count=1)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -4,6 +4,9 @@ from app.services.auth_service import AuthService
|
||||||
from app.schemas import LoginSchema
|
from app.schemas import LoginSchema
|
||||||
from app.exception import AuthException
|
from app.exception import AuthException
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
|
from app.models.entities import UserEntity
|
||||||
|
from app.schemas.response import LoginResponseSchema
|
||||||
|
from app.mapper import UserMapper
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -17,97 +20,180 @@ def auth_service(mock_user_repository):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def dummy_user():
|
def dummy_user_entity():
|
||||||
|
# Create a UserEntity instance with natural-looking data
|
||||||
|
return UserEntity(
|
||||||
|
id="6507a32a1f3b5e2dc8a45bf9",
|
||||||
|
email="budi@mail.com",
|
||||||
|
password=generate_password_hash("rahasia123"),
|
||||||
|
name="Budi Santoso",
|
||||||
|
locale="id-ID",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dummy_user_response():
|
||||||
|
# Create a mock response with natural-looking data
|
||||||
return MagicMock(
|
return MagicMock(
|
||||||
id="user123",
|
id="6507a32a1f3b5e2dc8a45bf9", email="budi@mail.com", name="Budi Santoso"
|
||||||
email="user@example.com",
|
|
||||||
password=generate_password_hash("secret"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- verify_google_id_token tests ---
|
# --- verify_google_id_token tests ---
|
||||||
|
|
||||||
|
|
||||||
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
||||||
def test_verify_google_existing_user(
|
def test_verify_google_existing_user(
|
||||||
mock_verify, auth_service, mock_user_repository, dummy_user
|
mock_verify,
|
||||||
|
auth_service,
|
||||||
|
mock_user_repository,
|
||||||
|
dummy_user_entity,
|
||||||
|
dummy_user_response,
|
||||||
):
|
):
|
||||||
# Simulate valid token
|
# Simulate valid token
|
||||||
mock_verify.return_value = {"sub": "google-id-123", "email": "user@example.com"}
|
mock_verify.return_value = {
|
||||||
mock_user_repository.get_by_google_id.return_value = dummy_user
|
"sub": "108762374589123456789",
|
||||||
|
"email": "budi@mail.com",
|
||||||
|
}
|
||||||
|
mock_user_repository.get_by_google_id.return_value = dummy_user_entity
|
||||||
|
|
||||||
user = auth_service.verify_google_id_token("valid_token")
|
# Setup the mapper to return our expected response
|
||||||
assert user == dummy_user
|
with patch(
|
||||||
mock_user_repository.get_by_google_id.assert_called_once()
|
"app.services.auth_service.UserMapper.user_entity_to_response"
|
||||||
|
) as mock_mapper:
|
||||||
|
mock_mapper.return_value = dummy_user_response
|
||||||
|
user = auth_service.verify_google_id_token("valid_token_string")
|
||||||
|
|
||||||
|
assert user == dummy_user_response
|
||||||
|
mock_user_repository.get_by_google_id.assert_called_once_with(
|
||||||
|
"108762374589123456789"
|
||||||
|
)
|
||||||
|
mock_mapper.assert_called_once_with(dummy_user_entity)
|
||||||
|
|
||||||
|
|
||||||
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
||||||
def test_verify_google_new_user(
|
def test_verify_google_new_user(
|
||||||
mock_verify, auth_service, mock_user_repository, dummy_user
|
mock_verify,
|
||||||
|
auth_service,
|
||||||
|
mock_user_repository,
|
||||||
|
dummy_user_entity,
|
||||||
|
dummy_user_response,
|
||||||
):
|
):
|
||||||
mock_verify.return_value = {
|
# Setup the Google payload with natural data
|
||||||
"sub": "new-google-id",
|
google_payload = {
|
||||||
"email": "newuser@example.com",
|
"sub": "117239875612345678901",
|
||||||
"name": "New User",
|
"email": "dewi@mail.com",
|
||||||
|
"name": "Dewi Sartika",
|
||||||
}
|
}
|
||||||
mock_user_repository.get_by_google_id.return_value = None
|
mock_verify.return_value = google_payload
|
||||||
mock_user_repository.insert_user.return_value = "new-user-id"
|
|
||||||
mock_user_repository.get_user_by_id.return_value = dummy_user
|
|
||||||
|
|
||||||
|
# Setup repository responses
|
||||||
|
mock_user_repository.get_by_google_id.return_value = None
|
||||||
|
mock_user_repository.insert_user.return_value = "65081fe3ab234cdef9876543"
|
||||||
|
mock_user_repository.get_user_by_id.return_value = dummy_user_entity
|
||||||
|
|
||||||
|
# Setup mappers
|
||||||
with patch(
|
with patch(
|
||||||
"app.services.auth_service.UserMapper.from_google_payload"
|
"app.services.auth_service.UserMapper.from_google_payload"
|
||||||
) as mock_mapper:
|
) as mock_from_google:
|
||||||
mock_mapper.return_value = dummy_user
|
with patch(
|
||||||
user = auth_service.verify_google_id_token("new_token")
|
"app.services.auth_service.UserMapper.user_entity_to_response"
|
||||||
|
) as mock_to_response:
|
||||||
|
# Configure the mocks
|
||||||
|
mock_from_google.return_value = dummy_user_entity
|
||||||
|
mock_to_response.return_value = dummy_user_response
|
||||||
|
|
||||||
assert user == dummy_user
|
# Call the method
|
||||||
mock_user_repository.insert_user.assert_called_once()
|
user = auth_service.verify_google_id_token("google_token_string")
|
||||||
mock_user_repository.get_user_by_id.assert_called_once_with(user_id="new-user-id")
|
|
||||||
|
# Assertions
|
||||||
|
assert user == dummy_user_response
|
||||||
|
mock_user_repository.get_by_google_id.assert_called_once_with(
|
||||||
|
"117239875612345678901"
|
||||||
|
)
|
||||||
|
mock_from_google.assert_called_once_with(
|
||||||
|
"117239875612345678901", "dewi@mail.com", google_payload
|
||||||
|
)
|
||||||
|
mock_user_repository.insert_user.assert_called_once_with(
|
||||||
|
user_data=dummy_user_entity
|
||||||
|
)
|
||||||
|
mock_user_repository.get_user_by_id.assert_called_once_with(
|
||||||
|
user_id="65081fe3ab234cdef9876543"
|
||||||
|
)
|
||||||
|
mock_to_response.assert_called_once_with(dummy_user_entity)
|
||||||
|
|
||||||
|
|
||||||
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
||||||
def test_verify_google_email_mismatch(
|
def test_verify_google_email_mismatch(
|
||||||
mock_verify, auth_service, mock_user_repository, dummy_user
|
mock_verify, auth_service, mock_user_repository, dummy_user_entity
|
||||||
):
|
):
|
||||||
mock_verify.return_value = {"sub": "google-id-123", "email": "wrong@example.com"}
|
# Setup mismatched email scenario with natural data
|
||||||
dummy_user.email = "correct@example.com"
|
mock_verify.return_value = {
|
||||||
mock_user_repository.get_by_google_id.return_value = dummy_user
|
"sub": "108762374589123456789",
|
||||||
|
"email": "dewi@mail.com",
|
||||||
|
}
|
||||||
|
dummy_user_entity.email = "budi@mail.com"
|
||||||
|
mock_user_repository.get_by_google_id.return_value = dummy_user_entity
|
||||||
|
|
||||||
|
# Test should raise exception
|
||||||
with pytest.raises(AuthException, match="Email not match"):
|
with pytest.raises(AuthException, match="Email not match"):
|
||||||
auth_service.verify_google_id_token("token")
|
auth_service.verify_google_id_token("token_string")
|
||||||
|
|
||||||
|
|
||||||
# @patch("app.services.auth_service.id_token.verify_oauth2_token")
|
@patch("app.services.auth_service.id_token.verify_oauth2_token")
|
||||||
# def test_verify_google_invalid_token(mock_verify, auth_service):
|
def test_verify_google_invalid_token(mock_verify, auth_service):
|
||||||
# mock_verify.side_effect = ValueError("Invalid token")
|
# Setup token verification failure
|
||||||
|
mock_verify.side_effect = ValueError("Token tidak valid")
|
||||||
|
|
||||||
# with pytest.raises(AuthException):
|
# Test should raise exception
|
||||||
# auth_service.verify_google_id_token("invalid_token")
|
with pytest.raises(Exception):
|
||||||
|
auth_service.verify_google_id_token("invalid_token_string")
|
||||||
|
|
||||||
|
|
||||||
# --- login tests ---
|
# --- login tests ---
|
||||||
|
def test_login_success(
|
||||||
|
auth_service, mock_user_repository, dummy_user_entity, dummy_user_response
|
||||||
|
):
|
||||||
|
# Setup repository
|
||||||
|
mock_user_repository.get_user_by_email.return_value = dummy_user_entity
|
||||||
|
|
||||||
|
# Setup mapper
|
||||||
|
with patch(
|
||||||
|
"app.services.auth_service.UserMapper.user_entity_to_response"
|
||||||
|
) as mock_mapper:
|
||||||
|
mock_mapper.return_value = dummy_user_response
|
||||||
|
|
||||||
|
# Call login with natural data
|
||||||
|
schema = LoginSchema(email="budi@mail.com", password="rahasia123")
|
||||||
|
user = auth_service.login(schema)
|
||||||
|
|
||||||
|
# Assertions
|
||||||
|
assert user == dummy_user_response
|
||||||
|
mock_user_repository.get_user_by_email.assert_called_once_with("budi@mail.com")
|
||||||
|
# Verify that password is set to None
|
||||||
|
assert dummy_user_entity.password is None
|
||||||
|
mock_mapper.assert_called_once_with(dummy_user_entity)
|
||||||
|
|
||||||
|
|
||||||
def test_login_success(auth_service, mock_user_repository, dummy_user):
|
def test_login_wrong_password(auth_service, mock_user_repository, dummy_user_entity):
|
||||||
mock_user_repository.get_user_by_email.return_value = dummy_user
|
# Setup repository with correct user
|
||||||
schema = LoginSchema(email="user@example.com", password="secret")
|
mock_user_repository.get_user_by_email.return_value = dummy_user_entity
|
||||||
|
|
||||||
|
# Login with wrong password
|
||||||
|
schema = LoginSchema(email="budi@mail.com", password="password_salah")
|
||||||
user = auth_service.login(schema)
|
user = auth_service.login(schema)
|
||||||
assert user.email == "user@example.com"
|
|
||||||
assert user.password is None
|
|
||||||
|
|
||||||
|
# Assertions
|
||||||
def test_login_wrong_password(auth_service, mock_user_repository, dummy_user):
|
|
||||||
mock_user_repository.get_user_by_email.return_value = dummy_user
|
|
||||||
schema = LoginSchema(email="user@example.com", password="wrong")
|
|
||||||
|
|
||||||
user = auth_service.login(schema)
|
|
||||||
assert user is None
|
assert user is None
|
||||||
|
mock_user_repository.get_user_by_email.assert_called_once_with("budi@mail.com")
|
||||||
|
|
||||||
|
|
||||||
def test_login_user_not_found(auth_service, mock_user_repository):
|
def test_login_user_not_found(auth_service, mock_user_repository):
|
||||||
|
# Setup repository to return no user
|
||||||
mock_user_repository.get_user_by_email.return_value = None
|
mock_user_repository.get_user_by_email.return_value = None
|
||||||
schema = LoginSchema(email="unknown@example.com", password="any")
|
|
||||||
|
|
||||||
|
# Login with unknown email
|
||||||
|
schema = LoginSchema(email="tidak_ada@mail.com", password="rahasia123")
|
||||||
user = auth_service.login(schema)
|
user = auth_service.login(schema)
|
||||||
|
|
||||||
|
# Assertions
|
||||||
assert user is None
|
assert user is None
|
||||||
|
mock_user_repository.get_user_by_email.assert_called_once_with("tidak_ada@mail.com")
|
||||||
|
|
|
@ -7,123 +7,302 @@ from app.schemas.response import HistoryResultSchema, QuizHistoryResponse
|
||||||
from app.models.entities import AnswerItemEntity, QuestionItemEntity
|
from app.models.entities import AnswerItemEntity, QuestionItemEntity
|
||||||
import datetime
|
import datetime
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
|
from app.helpers import DatetimeUtil
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_quiz_repository():
|
def mock_quiz_repository():
|
||||||
return MagicMock()
|
return MagicMock()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_answer_repository():
|
def mock_answer_repository():
|
||||||
return MagicMock()
|
return MagicMock()
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_session_repository():
|
||||||
|
return MagicMock()
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def history_service(mock_quiz_repository, mock_answer_repository):
|
def mock_user_repository():
|
||||||
return HistoryService(
|
return MagicMock()
|
||||||
quiz_repository=mock_quiz_repository, answer_repository=mock_answer_repository
|
|
||||||
)
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def history_service(
|
||||||
|
mock_quiz_repository,
|
||||||
|
mock_answer_repository,
|
||||||
|
mock_session_repository,
|
||||||
|
mock_user_repository,
|
||||||
|
):
|
||||||
|
return HistoryService(
|
||||||
|
quiz_repository=mock_quiz_repository,
|
||||||
|
answer_repository=mock_answer_repository,
|
||||||
|
session_repository=mock_session_repository,
|
||||||
|
user_repository=mock_user_repository,
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_history_by_user_id(
|
def test_get_history_by_user_id(
|
||||||
history_service, mock_answer_repository, mock_quiz_repository
|
history_service, mock_answer_repository, mock_quiz_repository
|
||||||
):
|
):
|
||||||
|
# Create realistic user answers with proper ObjectId format
|
||||||
mock_answers = [
|
mock_answers = [
|
||||||
UserAnswerEntity(
|
UserAnswerEntity(
|
||||||
id="answer1",
|
id=ObjectId("65a1b23c7d8e9f0123456789"),
|
||||||
session_id="",
|
session_id="65a1b23c7d8e9f0123456790",
|
||||||
quiz_id="6815da9f37a1ce472ba72819",
|
quiz_id="65a1b23c7d8e9f0123456791",
|
||||||
user_id="user123",
|
user_id="65a1b23c7d8e9f0123456792",
|
||||||
total_correct=8,
|
total_correct=8,
|
||||||
total_score=80,
|
total_score=80,
|
||||||
answered_at=datetime.datetime(2024, 1, 1, 10, 30, 0),
|
answered_at=datetime.datetime(2024, 5, 15, 14, 30, 22),
|
||||||
|
answers=[],
|
||||||
|
),
|
||||||
|
UserAnswerEntity(
|
||||||
|
id=ObjectId("65a1b23c7d8e9f0123456793"),
|
||||||
|
session_id="65a1b23c7d8e9f0123456794",
|
||||||
|
quiz_id="65a1b23c7d8e9f0123456795",
|
||||||
|
user_id="65a1b23c7d8e9f0123456792",
|
||||||
|
total_correct=6,
|
||||||
|
total_score=60,
|
||||||
|
answered_at=datetime.datetime(2024, 5, 10, 9, 45, 12),
|
||||||
answers=[],
|
answers=[],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Create realistic quiz data with proper ObjectId format
|
||||||
mock_quiz = [
|
mock_quiz = [
|
||||||
QuizEntity(
|
QuizEntity(
|
||||||
_id=ObjectId("6815da9f37a1ce472ba72819"),
|
_id=ObjectId("65a1b23c7d8e9f0123456791"),
|
||||||
subject_id="",
|
subject_id="65a1b23c7d8e9f0123456796",
|
||||||
title="Quiz Matematika",
|
title="Persiapan UN Matematika Kelas 12",
|
||||||
description="Soal dasar matematika",
|
description="Quiz untuk mempersiapkan Ujian Nasional Matematika SMA",
|
||||||
total_quiz=10,
|
total_quiz=10,
|
||||||
author_id="author1",
|
author_id="65a1b23c7d8e9f0123456797",
|
||||||
date=datetime.datetime(2024, 2, 2, 14, 0, 0),
|
date=datetime.datetime(2024, 5, 1, 8, 0, 0),
|
||||||
|
question_listings=[],
|
||||||
|
),
|
||||||
|
QuizEntity(
|
||||||
|
_id=ObjectId("65a1b23c7d8e9f0123456795"),
|
||||||
|
subject_id="65a1b23c7d8e9f0123456798",
|
||||||
|
title="Olimpiade Fisika SMA 2024",
|
||||||
|
description="Latihan soal untuk persiapan olimpiade fisika tingkat provinsi",
|
||||||
|
total_quiz=10,
|
||||||
|
author_id="65a1b23c7d8e9f0123456797",
|
||||||
|
date=datetime.datetime(2024, 5, 2, 10, 0, 0),
|
||||||
question_listings=[],
|
question_listings=[],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
mock_answer_repository.get_by_user.return_value = mock_answers
|
mock_answer_repository.get_by_user.return_value = mock_answers
|
||||||
mock_quiz_repository.get_by_ids.return_value = mock_quiz
|
mock_quiz_repository.get_by_ids.return_value = mock_quiz
|
||||||
|
|
||||||
result = history_service.get_history_by_user_id("user123")
|
# Test with realistic user ID
|
||||||
|
result = history_service.get_history_by_user_id("65a1b23c7d8e9f0123456792")
|
||||||
assert len(result) == 1
|
|
||||||
|
# Assertions
|
||||||
|
assert len(result) == 2
|
||||||
assert isinstance(result[0], HistoryResultSchema)
|
assert isinstance(result[0], HistoryResultSchema)
|
||||||
assert result[0].quiz_id == "6815da9f37a1ce472ba72819"
|
assert result[0].quiz_id == "65a1b23c7d8e9f0123456791"
|
||||||
|
assert result[0].title == "Persiapan UN Matematika Kelas 12"
|
||||||
assert result[0].total_correct == 8
|
assert result[0].total_correct == 8
|
||||||
assert result[0].total_question == 10
|
assert result[0].total_question == 10
|
||||||
|
assert result[1].quiz_id == "65a1b23c7d8e9f0123456795"
|
||||||
|
assert result[1].title == "Olimpiade Fisika SMA 2024"
|
||||||
|
assert result[1].total_correct == 6
|
||||||
|
assert result[1].total_question == 10
|
||||||
|
|
||||||
def test_get_history_by_user_id_no_data(history_service, mock_answer_repository):
|
def test_get_history_by_user_id_no_data(history_service, mock_answer_repository):
|
||||||
mock_answer_repository.get_by_user.return_value = []
|
mock_answer_repository.get_by_user.return_value = []
|
||||||
|
result = history_service.get_history_by_user_id("65a1b23c7d8e9f0123456792")
|
||||||
result = history_service.get_history_by_user_id("user123")
|
|
||||||
|
|
||||||
assert result == []
|
assert result == []
|
||||||
|
|
||||||
|
|
||||||
def test_get_history_by_answer_id(
|
def test_get_history_by_answer_id(
|
||||||
history_service, mock_answer_repository, mock_quiz_repository
|
history_service, mock_answer_repository, mock_quiz_repository
|
||||||
):
|
):
|
||||||
|
# Create a realistic answer with detailed answer items
|
||||||
mock_answer = UserAnswerEntity(
|
mock_answer = UserAnswerEntity(
|
||||||
id="answer1",
|
id=ObjectId("65a1b23c7d8e9f0123456799"),
|
||||||
session_id="",
|
session_id="65a1b23c7d8e9f0123456790",
|
||||||
user_id="user1",
|
user_id="65a1b23c7d8e9f0123456792",
|
||||||
quiz_id="quiz1",
|
quiz_id="65a1b23c7d8e9f0123456791",
|
||||||
total_correct=7,
|
total_correct=7,
|
||||||
total_score=70,
|
total_score=70,
|
||||||
answered_at=datetime.datetime(2024, 2, 2, 14, 0, 0),
|
answered_at=datetime.datetime(2024, 5, 18, 14, 22, 30),
|
||||||
answers=[
|
answers=[
|
||||||
AnswerItemEntity(
|
AnswerItemEntity(
|
||||||
question_index=0,
|
question_index=0,
|
||||||
answer="B",
|
answer="B",
|
||||||
is_correct=True,
|
is_correct=True,
|
||||||
time_spent=12,
|
time_spent=15,
|
||||||
|
),
|
||||||
|
AnswerItemEntity(
|
||||||
|
question_index=1,
|
||||||
|
answer="C",
|
||||||
|
is_correct=True,
|
||||||
|
time_spent=20,
|
||||||
|
),
|
||||||
|
AnswerItemEntity(
|
||||||
|
question_index=2,
|
||||||
|
answer="A",
|
||||||
|
is_correct=False,
|
||||||
|
time_spent=25,
|
||||||
|
),
|
||||||
|
AnswerItemEntity(
|
||||||
|
question_index=3,
|
||||||
|
answer="D",
|
||||||
|
is_correct=True,
|
||||||
|
time_spent=10,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Create a realistic quiz with detailed questions
|
||||||
mock_quiz = QuizEntity(
|
mock_quiz = QuizEntity(
|
||||||
id="quiz1",
|
id=ObjectId("65a1b23c7d8e9f0123456791"),
|
||||||
title="Quiz IPA",
|
title="Geografi Indonesia",
|
||||||
description="Ilmu Pengetahuan Alam",
|
description="Quiz tentang letak geografis dan kondisi alam Indonesia",
|
||||||
subject_id="subject1",
|
subject_id="65a1b23c7d8e9f0123456796",
|
||||||
date=datetime.datetime(2025, 5, 5, 0, 0),
|
date=datetime.datetime(2024, 5, 1, 8, 0, 0),
|
||||||
total_quiz=10,
|
total_quiz=10,
|
||||||
author_id="author1",
|
author_id="65a1b23c7d8e9f0123456797",
|
||||||
question_listings=[
|
question_listings=[
|
||||||
QuestionItemEntity(
|
QuestionItemEntity(
|
||||||
index=0,
|
index=0,
|
||||||
question="Apa ibu kota Indonesia?",
|
question="Apa ibu kota Indonesia?",
|
||||||
type="multiple_choice",
|
type="multiple_choice",
|
||||||
target_answer="B",
|
target_answer="B",
|
||||||
options=["A. Surabaya", "B. Jakarta", "C. Bandung"],
|
options=["A. Surabaya", "B. Jakarta", "C. Bandung", "D. Medan"],
|
||||||
duration=20,
|
duration=30,
|
||||||
|
),
|
||||||
|
QuestionItemEntity(
|
||||||
|
index=1,
|
||||||
|
question="Gunung tertinggi di Indonesia adalah?",
|
||||||
|
type="multiple_choice",
|
||||||
|
target_answer="C",
|
||||||
|
options=["A. Merapi", "B. Semeru", "C. Puncak Jaya", "D. Kerinci"],
|
||||||
|
duration=30,
|
||||||
|
),
|
||||||
|
QuestionItemEntity(
|
||||||
|
index=2,
|
||||||
|
question="Indonesia memiliki berapa provinsi?",
|
||||||
|
type="multiple_choice",
|
||||||
|
target_answer="B",
|
||||||
|
options=["A. 33", "B. 34", "C. 35", "D. 36"],
|
||||||
|
duration=30,
|
||||||
|
),
|
||||||
|
QuestionItemEntity(
|
||||||
|
index=3,
|
||||||
|
question="Selat yang memisahkan Pulau Jawa dan Sumatera adalah?",
|
||||||
|
type="multiple_choice",
|
||||||
|
target_answer="D",
|
||||||
|
options=["A. Selat Makassar", "B. Selat Karimata", "C. Selat Bali", "D. Selat Sunda"],
|
||||||
|
duration=30,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_answer_repository.get_by_id.return_value = mock_answer
|
mock_answer_repository.get_by_id.return_value = mock_answer
|
||||||
mock_quiz_repository.get_by_id.return_value = mock_quiz
|
mock_quiz_repository.get_by_id.return_value = mock_quiz
|
||||||
|
|
||||||
result = history_service.get_history_by_answer_id("answer1")
|
# Test with realistic answer ID
|
||||||
|
result = history_service.get_history_by_answer_id("65a1b23c7d8e9f0123456799")
|
||||||
|
|
||||||
|
# Assertions
|
||||||
assert isinstance(result, QuizHistoryResponse)
|
assert isinstance(result, QuizHistoryResponse)
|
||||||
|
assert result.quiz_id == str(mock_quiz.id)
|
||||||
|
assert result.title == "Geografi Indonesia"
|
||||||
|
assert result.description == "Quiz tentang letak geografis dan kondisi alam Indonesia"
|
||||||
assert result.total_correct == 7
|
assert result.total_correct == 7
|
||||||
assert result.total_score == 70
|
assert result.total_score == 70
|
||||||
assert result.total_solve_time == 12
|
assert result.total_solve_time == 70 # Sum of all time_spent (15+20+25+10)
|
||||||
assert len(result.question_listings) == 1
|
assert len(result.question_listings) == 4
|
||||||
|
|
||||||
|
# Verify individual questions and answers
|
||||||
|
assert result.question_listings[0].question == "Apa ibu kota Indonesia?"
|
||||||
assert result.question_listings[0].is_correct is True
|
assert result.question_listings[0].is_correct is True
|
||||||
assert result.question_listings[0].user_answer == "B"
|
assert result.question_listings[0].user_answer == "B"
|
||||||
|
assert result.question_listings[0].time_spent == 15
|
||||||
|
|
||||||
|
assert result.question_listings[2].question == "Indonesia memiliki berapa provinsi?"
|
||||||
|
assert result.question_listings[2].is_correct is False
|
||||||
|
assert result.question_listings[2].user_answer == "A"
|
||||||
|
assert result.question_listings[2].time_spent == 25
|
||||||
|
|
||||||
|
def test_get_session_history(
|
||||||
|
history_service,
|
||||||
|
mock_session_repository,
|
||||||
|
mock_answer_repository,
|
||||||
|
mock_user_repository,
|
||||||
|
):
|
||||||
|
# Create realistic session data
|
||||||
|
mock_session = MagicMock()
|
||||||
|
session_id = ObjectId("65a1b23c7d8e9f0123456800")
|
||||||
|
mock_session.id = session_id
|
||||||
|
mock_session.quiz_id = ObjectId("65a1b23c7d8e9f0123456791")
|
||||||
|
mock_session.title = "Olimpiade Matematika Kelas 11"
|
||||||
|
mock_session.room_code = "MATH11A"
|
||||||
|
mock_session.host_id = ObjectId("65a1b23c7d8e9f0123456801")
|
||||||
|
mock_session.participants = [
|
||||||
|
{"id": "65a1b23c7d8e9f0123456802"},
|
||||||
|
{"id": "65a1b23c7d8e9f0123456803"},
|
||||||
|
{"id": "65a1b23c7d8e9f0123456804"}
|
||||||
|
]
|
||||||
|
mock_session.created_at = datetime.datetime(2024, 5, 20, 9, 0, 0)
|
||||||
|
mock_session.started_at = datetime.datetime(2024, 5, 20, 9, 15, 0)
|
||||||
|
mock_session.ended_at = datetime.datetime(2024, 5, 20, 10, 0, 0)
|
||||||
|
|
||||||
|
# Mock repository responses
|
||||||
|
mock_session_repository.find_by_session_id.return_value = mock_session
|
||||||
|
|
||||||
|
# Mock user answers with realistic scores
|
||||||
|
mock_answer1 = MagicMock()
|
||||||
|
mock_answer1.total_score = 85
|
||||||
|
|
||||||
|
mock_answer2 = MagicMock()
|
||||||
|
mock_answer2.total_score = 92
|
||||||
|
|
||||||
|
mock_answer3 = MagicMock()
|
||||||
|
mock_answer3.total_score = 78
|
||||||
|
|
||||||
|
# Mock users with realistic Indonesian names
|
||||||
|
mock_user1 = MagicMock()
|
||||||
|
mock_user1.id = "65a1b23c7d8e9f0123456802"
|
||||||
|
mock_user1.name = "Ahmad Fauzi"
|
||||||
|
|
||||||
|
mock_user2 = MagicMock()
|
||||||
|
mock_user2.id = "65a1b23c7d8e9f0123456803"
|
||||||
|
mock_user2.name = "Siti Nurhaliza"
|
||||||
|
|
||||||
|
mock_user3 = MagicMock()
|
||||||
|
mock_user3.id = "65a1b23c7d8e9f0123456804"
|
||||||
|
mock_user3.name = "Rudi Hermawan"
|
||||||
|
|
||||||
|
# Set up mock returns
|
||||||
|
mock_answer_repository.get_by_userid_and_sessionid.side_effect = [
|
||||||
|
mock_answer1,
|
||||||
|
mock_answer2,
|
||||||
|
mock_answer3
|
||||||
|
]
|
||||||
|
mock_user_repository.get_user_by_id.side_effect = [
|
||||||
|
mock_user1,
|
||||||
|
mock_user2,
|
||||||
|
mock_user3
|
||||||
|
]
|
||||||
|
|
||||||
|
# Call the function with realistic session ID
|
||||||
|
result = history_service.get_session_history(str(session_id))
|
||||||
|
|
||||||
|
# Assertions
|
||||||
|
assert result == mock_session
|
||||||
|
assert str(result.id) == str(session_id)
|
||||||
|
assert len(result.participants) == 3
|
||||||
|
|
||||||
|
# Check participant details
|
||||||
|
assert result.participants[0]["name"] == "Ahmad Fauzi"
|
||||||
|
assert result.participants[0]["score"] == 85
|
||||||
|
assert result.participants[1]["name"] == "Siti Nurhaliza"
|
||||||
|
assert result.participants[1]["score"] == 92
|
||||||
|
assert result.participants[2]["name"] == "Rudi Hermawan"
|
||||||
|
assert result.participants[2]["score"] == 78
|
||||||
|
|
||||||
|
# Ensure DatetimeUtil was called to format the dates
|
||||||
|
assert result.created_at == DatetimeUtil.to_string(datetime.datetime(2024, 5, 20, 9, 0, 0))
|
||||||
|
assert result.started_at == DatetimeUtil.to_string(datetime.datetime(2024, 5, 20, 9, 15, 0))
|
||||||
|
assert result.ended_at == DatetimeUtil.to_string(datetime.datetime(2024, 5, 20, 10, 0, 0))
|
Loading…
Reference in New Issue