1
0
Files
medical-notes/quiz/quiz/tests/test_views.py
Johan Dahlin 8c0aaa9620
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 1m47s
vault backup: 2025-12-23 16:41:40
2025-12-23 16:41:40 +01:00

308 lines
10 KiB
Python

from django.test import TestCase, Client
from django.urls import reverse
from quiz.models import Question, QuizUser, QuizSession, QuizResult, Course, Exam, Tag, Option
class QuizViewsTestCase(TestCase):
"""Comprehensive tests for all quiz endpoints"""
def setUp(self):
"""Set up test data"""
self.client = Client()
# Ensure session exists and get its key
s = self.client.session
s.save()
session_key = s.session_key
# Create test user with the same session key
self.user = QuizUser.objects.create(session_key=session_key)
# Create test course
self.course = Course.objects.create(name="Test Course")
# Create test exam
self.exam = Exam.objects.create(
name="Test Exam",
course=self.course,
date="2025-01-01" # Required field
)
# Create test tags
self.tag1 = Tag.objects.create(name="Tag 1", slug="tag-1")
self.tag2 = Tag.objects.create(name="Tag 2", slug="tag-2")
# Create test questions
self.question1 = Question.objects.create(
text="Test question 1?",
correct_answer="A",
exam=self.exam,
file_path="test1.md"
)
self.question1.tags.add(self.tag1)
Option.objects.create(question=self.question1, letter="A", text="Answer A")
Option.objects.create(question=self.question1, letter="B", text="Answer B")
self.question2 = Question.objects.create(
text="Test question 2 (multi)?",
correct_answer="A,B",
exam=self.exam,
file_path="test2.md"
)
self.question2.tags.add(self.tag1, self.tag2)
Option.objects.create(question=self.question2, letter="A", text="Answer A")
Option.objects.create(question=self.question2, letter="B", text="Answer B")
Option.objects.create(question=self.question2, letter="C", text="Answer C")
# Set user in session
session = self.client.session
session['quiz_user_id'] = self.user.id
session.save()
def test_index_view(self):
"""Test dashboard index view"""
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Snabbstart')
self.assertIn('active_sessions', response.context)
self.assertIn('form', response.context)
def test_create_quiz(self):
"""Test quiz creation"""
response = self.client.post(reverse('create_quiz'), {
'course': self.course.id,
'tags': [self.tag1.id],
})
self.assertEqual(response.status_code, 302) # Redirect
# Verify session was created
session = QuizSession.objects.filter(user=self.user).first()
self.assertIsNotNone(session)
self.assertEqual(session.course, self.course)
self.assertTrue(session.is_active)
def test_quiz_mode_view(self):
"""Test dedicated quiz mode view"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
response = self.client.get(reverse('quiz_mode', args=[session.id]))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Test Course')
self.assertIn('session', response.context)
def test_quiz_question_view(self):
"""Test quiz question endpoint"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
response = self.client.get(reverse('quiz_question', args=[session.id]))
self.assertEqual(response.status_code, 200)
self.assertIn('question', response.context)
self.assertIn('session', response.context)
def test_navigate_question(self):
"""Test question navigation"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
# Test next navigation
response = self.client.get(
reverse('navigate_question', args=[session.id, 'next']),
{'q': self.question1.id}
)
self.assertEqual(response.status_code, 200)
# Test previous navigation
response = self.client.get(
reverse('navigate_question', args=[session.id, 'previous']),
{'q': self.question2.id}
)
self.assertEqual(response.status_code, 200)
def test_submit_single_answer(self):
"""Test submitting a single-choice answer"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
response = self.client.post(
reverse('submit_answer', args=[session.id]),
{
'question_id': self.question1.id,
'answer': 'A'
}
)
self.assertEqual(response.status_code, 200)
# Verify result was created
result = QuizResult.objects.get(
user=self.user,
question=self.question1,
quiz_session=session
)
self.assertEqual(result.selected_answer, 'A')
self.assertTrue(result.is_correct)
def test_submit_multi_answer(self):
"""Test submitting a multi-choice answer"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
# Test correct multi-answer (order shouldn't matter)
response = self.client.post(
reverse('submit_answer', args=[session.id]),
{
'question_id': self.question2.id,
'answer': 'B,A' # Reversed order
}
)
self.assertEqual(response.status_code, 200)
result = QuizResult.objects.get(
user=self.user,
question=self.question2,
quiz_session=session
)
self.assertTrue(result.is_correct) # Should be correct despite order
def test_submit_difficulty(self):
"""Test submitting FSRS difficulty rating"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
# First submit an answer
QuizResult.objects.create(
user=self.user,
question=self.question1,
quiz_session=session,
selected_answer='A',
is_correct=True
)
# Then submit difficulty
response = self.client.post(
reverse('submit_difficulty', args=[session.id]),
{
'question_id': self.question1.id,
'difficulty': 'easy'
}
)
self.assertEqual(response.status_code, 200)
# Verify difficulty was saved
result = QuizResult.objects.get(
user=self.user,
question=self.question1,
quiz_session=session
)
self.assertEqual(result.difficulty, 'easy')
def test_close_quiz(self):
"""Test closing a quiz session"""
session = QuizSession.objects.create(
user=self.user,
course=self.course,
is_active=True
)
response = self.client.post(reverse('close_quiz', args=[session.id]))
self.assertEqual(response.status_code, 302) # Redirect to index
# Verify session was deactivated
session.refresh_from_db()
self.assertFalse(session.is_active)
def test_invalid_session_access(self):
"""Test accessing another user's session"""
other_user = QuizUser.objects.create(session_key="other_session_key")
session = QuizSession.objects.create(
user=other_user,
course=self.course
)
# Try to access it
response = self.client.get(reverse('quiz_mode', args=[session.id]))
self.assertEqual(response.status_code, 404)
def test_answer_without_question_id(self):
"""Test error handling for missing question_id"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
response = self.client.post(
reverse('submit_answer', args=[session.id]),
{'answer': 'A'} # Missing question_id
)
self.assertEqual(response.status_code, 400)
def test_difficulty_without_result(self):
"""Test error handling for difficulty without existing result"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
response = self.client.post(
reverse('submit_difficulty', args=[session.id]),
{
'question_id': self.question1.id,
'difficulty': 'easy'
}
)
self.assertEqual(response.status_code, 404)
def test_answer_normalization(self):
"""Test that multi-choice answers are normalized correctly"""
session = QuizSession.objects.create(
user=self.user,
course=self.course
)
# Submit answers in different orders
test_cases = [
('A,B', True), # Correct order
('B,A', True), # Reversed order
('A,C', False), # Wrong answer
('A', False), # Incomplete answer
]
for answer, expected_correct in test_cases:
result = QuizResult.objects.filter(
user=self.user,
question=self.question2,
quiz_session=session
).delete() # Clean up
response = self.client.post(
reverse('submit_answer', args=[session.id]),
{
'question_id': self.question2.id,
'answer': answer
}
)
self.assertEqual(response.status_code, 200)
result = QuizResult.objects.get(
user=self.user,
question=self.question2,
quiz_session=session
)
self.assertEqual(result.is_correct, expected_correct,
f"Answer '{answer}' should be {'correct' if expected_correct else 'incorrect'}")