Pamela Fox
commited on
Commit
·
6768aaa
1
Parent(s):
f243d4f
tests
Browse files- quizsite/production.py +1 -1
- quizzes/models.py +1 -16
- quizzes/templates/quizzes/display.html +4 -2
- quizzes/tests.py +113 -2
- quizzes/urls.py +1 -1
- quizzes/views.py +5 -4
quizsite/production.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from .settings import *
|
| 2 |
import os
|
| 3 |
|
| 4 |
# Configure the domain name using the environment variable
|
|
|
|
| 1 |
+
from .settings import * # noqa
|
| 2 |
import os
|
| 3 |
|
| 4 |
# Configure the domain name using the environment variable
|
quizzes/models.py
CHANGED
|
@@ -6,22 +6,7 @@ class Quiz(models.Model):
|
|
| 6 |
name = models.CharField(max_length=100)
|
| 7 |
|
| 8 |
def __str__(self):
|
| 9 |
-
return
|
| 10 |
-
|
| 11 |
-
def display(self):
|
| 12 |
-
# Display the quiz name
|
| 13 |
-
print(f"Welcome to the quiz on {self.name}!")
|
| 14 |
-
# Initialize the correct counter to 0
|
| 15 |
-
correct_count = 0
|
| 16 |
-
# Iterate through the questions
|
| 17 |
-
# Display each question
|
| 18 |
-
# Increment the correct counter accordingly
|
| 19 |
-
for question in self.questions:
|
| 20 |
-
question.display()
|
| 21 |
-
if question.answer_status == "correct":
|
| 22 |
-
correct_count += 1
|
| 23 |
-
# Print the ratio of correct/total
|
| 24 |
-
print(f"You got {correct_count}/{len(self.questions)} correct.")
|
| 25 |
|
| 26 |
|
| 27 |
class Question(models.Model):
|
|
|
|
| 6 |
name = models.CharField(max_length=100)
|
| 7 |
|
| 8 |
def __str__(self):
|
| 9 |
+
return self.name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
|
| 12 |
class Question(models.Model):
|
quizzes/templates/quizzes/display.html
CHANGED
|
@@ -11,6 +11,7 @@
|
|
| 11 |
<h1>Quiz: {{ quiz.name }}</h1>
|
| 12 |
|
| 13 |
<section class="bg-warning" style="padding:12px">
|
|
|
|
| 14 |
<form id="question-form" action="{% url 'quizzes:grade_question' question.id %}" method="post">
|
| 15 |
{% csrf_token %}
|
| 16 |
|
|
@@ -41,10 +42,11 @@
|
|
| 41 |
<button type="submit" class="btn btn-primary">Check answers</button>
|
| 42 |
</form>
|
| 43 |
|
| 44 |
-
|
| 45 |
<div id="question-feedback" style="margin-top:16px">
|
| 46 |
</div>
|
| 47 |
-
|
|
|
|
|
|
|
| 48 |
</section>
|
| 49 |
|
| 50 |
{% if next_question %}
|
|
|
|
| 11 |
<h1>Quiz: {{ quiz.name }}</h1>
|
| 12 |
|
| 13 |
<section class="bg-warning" style="padding:12px">
|
| 14 |
+
{% if question %}
|
| 15 |
<form id="question-form" action="{% url 'quizzes:grade_question' question.id %}" method="post">
|
| 16 |
{% csrf_token %}
|
| 17 |
|
|
|
|
| 42 |
<button type="submit" class="btn btn-primary">Check answers</button>
|
| 43 |
</form>
|
| 44 |
|
|
|
|
| 45 |
<div id="question-feedback" style="margin-top:16px">
|
| 46 |
</div>
|
| 47 |
+
{% else %}
|
| 48 |
+
Sorry, that question doesn't exist in this quiz.
|
| 49 |
+
{% endif %}
|
| 50 |
</section>
|
| 51 |
|
| 52 |
{% if next_question %}
|
quizzes/tests.py
CHANGED
|
@@ -1,3 +1,114 @@
|
|
| 1 |
-
|
|
|
|
| 2 |
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.test import TestCase
|
| 2 |
+
from django.urls import reverse
|
| 3 |
|
| 4 |
+
from .models import Quiz, Question, FreeTextAnswer, MultipleChoiceAnswer
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def create_quiz():
|
| 8 |
+
quiz = Quiz.objects.create(name="Butterflies")
|
| 9 |
+
question = Question.objects.create(quiz=quiz, prompt="What plant do Swallowtail caterpillars eat?")
|
| 10 |
+
answer = MultipleChoiceAnswer.objects.create(
|
| 11 |
+
question=question, correct_answer="Dill", choices=["Thistle", "Milkweed", "Dill"]
|
| 12 |
+
)
|
| 13 |
+
return quiz, question, answer
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class FreeTextAnswerModelTests(TestCase):
|
| 17 |
+
def test_case_insensitive(self):
|
| 18 |
+
ans = FreeTextAnswer(correct_answer="Milkweed", case_sensitive=False)
|
| 19 |
+
self.assertTrue(ans.is_correct("Milkweed"))
|
| 20 |
+
self.assertTrue(ans.is_correct("milkweed"))
|
| 21 |
+
self.assertFalse(ans.is_correct("thistle"))
|
| 22 |
+
|
| 23 |
+
def test_case_sensitive(self):
|
| 24 |
+
ans = FreeTextAnswer(correct_answer="Armeria Maritima", case_sensitive=True)
|
| 25 |
+
self.assertFalse(ans.is_correct("armeria maritima"))
|
| 26 |
+
self.assertTrue(ans.is_correct("Armeria Maritima"))
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class MultipleChoiceAnswerModelTests(TestCase):
|
| 30 |
+
def test_choices(self):
|
| 31 |
+
ans = MultipleChoiceAnswer(correct_answer="Dill", choices=["Milkweed", "Dill", "Thistle"])
|
| 32 |
+
self.assertTrue(ans.is_correct("Dill"))
|
| 33 |
+
self.assertFalse(ans.is_correct("dill"))
|
| 34 |
+
self.assertFalse(ans.is_correct("Milkweed"))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class QuizModelTests(TestCase):
|
| 38 |
+
def test_quiz_relations(self):
|
| 39 |
+
quiz = Quiz.objects.create(name="Butterflies")
|
| 40 |
+
q1 = Question.objects.create(quiz=quiz, prompt="What plant do Swallowtail caterpillars eat?")
|
| 41 |
+
a1 = MultipleChoiceAnswer.objects.create(
|
| 42 |
+
question=q1, correct_answer="Dill", choices=["Thistle", "Milkweed", "Dill"]
|
| 43 |
+
)
|
| 44 |
+
q2 = Question.objects.create(quiz=quiz, prompt="What plant do Monarch caterpillars eat?")
|
| 45 |
+
a2 = FreeTextAnswer.objects.create(question=q2, correct_answer="Milkweed", case_sensitive=False)
|
| 46 |
+
self.assertEqual(len(quiz.question_set.all()), 2)
|
| 47 |
+
self.assertEqual(q1.multiplechoiceanswer, a1)
|
| 48 |
+
self.assertEqual(q2.freetextanswer, a2)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class IndexViewTests(TestCase):
|
| 52 |
+
def test_no_quizzes(self):
|
| 53 |
+
response = self.client.get(reverse("quizzes:index"))
|
| 54 |
+
self.assertEqual(response.status_code, 200)
|
| 55 |
+
self.assertContains(response, "No quizzes are available.")
|
| 56 |
+
self.assertQuerysetEqual(response.context["quiz_list"], [])
|
| 57 |
+
|
| 58 |
+
def test_one_quiz(self):
|
| 59 |
+
quiz, _, _ = create_quiz()
|
| 60 |
+
response = self.client.get(reverse("quizzes:index"))
|
| 61 |
+
self.assertQuerysetEqual(
|
| 62 |
+
response.context["quiz_list"],
|
| 63 |
+
[quiz],
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class DisplayQuizViewTests(TestCase):
|
| 68 |
+
def test_quiz_404(self):
|
| 69 |
+
url = reverse("quizzes:display_quiz", args=(12,))
|
| 70 |
+
response = self.client.get(url)
|
| 71 |
+
self.assertEqual(response.status_code, 404)
|
| 72 |
+
|
| 73 |
+
def test_quiz_redirects(self):
|
| 74 |
+
quiz, question, _ = create_quiz()
|
| 75 |
+
url = reverse("quizzes:display_quiz", args=(quiz.pk,))
|
| 76 |
+
response = self.client.get(url)
|
| 77 |
+
self.assertRedirects(response, reverse("quizzes:display_question", args=(quiz.pk, question.pk)))
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
class DisplayQuestionViewTests(TestCase):
|
| 81 |
+
def test_quiz_404(self):
|
| 82 |
+
url = reverse("quizzes:display_question", args=(12, 1))
|
| 83 |
+
response = self.client.get(url)
|
| 84 |
+
self.assertEqual(response.status_code, 404)
|
| 85 |
+
|
| 86 |
+
def test_question_404(self):
|
| 87 |
+
quiz, question, _ = create_quiz()
|
| 88 |
+
url = reverse("quizzes:display_question", args=(quiz.pk, question.pk + 100))
|
| 89 |
+
response = self.client.get(url)
|
| 90 |
+
self.assertContains(response, "that question doesn't exist")
|
| 91 |
+
|
| 92 |
+
def test_quiz_question_exists(self):
|
| 93 |
+
quiz, question, answer = create_quiz()
|
| 94 |
+
|
| 95 |
+
url = reverse("quizzes:display_question", args=(quiz.pk, question.pk))
|
| 96 |
+
response = self.client.get(url)
|
| 97 |
+
self.assertContains(response, quiz.name)
|
| 98 |
+
self.assertContains(response, question.prompt)
|
| 99 |
+
self.assertContains(response, answer.choices[0])
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class GradeQuestionViewTests(TestCase):
|
| 103 |
+
def test_question_404(self):
|
| 104 |
+
url = reverse("quizzes:grade_question", args=(12,))
|
| 105 |
+
response = self.client.get(url)
|
| 106 |
+
self.assertEqual(response.status_code, 404)
|
| 107 |
+
|
| 108 |
+
def test_question_correct(self):
|
| 109 |
+
_, question, answer = create_quiz()
|
| 110 |
+
|
| 111 |
+
url = reverse("quizzes:grade_question", args=(question.pk,))
|
| 112 |
+
response = self.client.post(url, {"answer": answer.correct_answer})
|
| 113 |
+
self.assertTrue(response.context["is_correct"])
|
| 114 |
+
self.assertEqual(response.context["correct_answer"], answer.correct_answer)
|
quizzes/urls.py
CHANGED
|
@@ -5,7 +5,7 @@ from . import views
|
|
| 5 |
app_name = "quizzes"
|
| 6 |
|
| 7 |
urlpatterns = [
|
| 8 |
-
path("", views.
|
| 9 |
path("<int:quiz_id>/", views.display_quiz, name="display_quiz"),
|
| 10 |
path("<int:quiz_id>/questions/<int:question_id>", views.display_question, name="display_question"),
|
| 11 |
path("questions/<int:question_id>/grade/", views.grade_question, name="grade_question"),
|
|
|
|
| 5 |
app_name = "quizzes"
|
| 6 |
|
| 7 |
urlpatterns = [
|
| 8 |
+
path("", views.IndexView.as_view(), name="index"),
|
| 9 |
path("<int:quiz_id>/", views.display_quiz, name="display_quiz"),
|
| 10 |
path("<int:quiz_id>/questions/<int:question_id>", views.display_question, name="display_question"),
|
| 11 |
path("questions/<int:question_id>/grade/", views.grade_question, name="grade_question"),
|
quizzes/views.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
from django.shortcuts import get_object_or_404, render, redirect
|
| 2 |
from django.urls import reverse
|
|
|
|
| 3 |
|
| 4 |
from .models import Quiz, Question
|
| 5 |
|
| 6 |
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
return render(request, "quizzes/index.html", context)
|
| 11 |
|
| 12 |
|
| 13 |
def display_quiz(request, quiz_id):
|
|
@@ -26,6 +26,7 @@ def display_question(request, quiz_id, question_id):
|
|
| 26 |
current_question = question
|
| 27 |
if ind != len(questions) - 1:
|
| 28 |
next_question = questions[ind + 1]
|
|
|
|
| 29 |
return render(
|
| 30 |
request,
|
| 31 |
"quizzes/display.html",
|
|
|
|
| 1 |
from django.shortcuts import get_object_or_404, render, redirect
|
| 2 |
from django.urls import reverse
|
| 3 |
+
from django.views import generic
|
| 4 |
|
| 5 |
from .models import Quiz, Question
|
| 6 |
|
| 7 |
|
| 8 |
+
class IndexView(generic.ListView):
|
| 9 |
+
model = Quiz
|
| 10 |
+
template_name = "quizzes/index.html"
|
|
|
|
| 11 |
|
| 12 |
|
| 13 |
def display_quiz(request, quiz_id):
|
|
|
|
| 26 |
current_question = question
|
| 27 |
if ind != len(questions) - 1:
|
| 28 |
next_question = questions[ind + 1]
|
| 29 |
+
|
| 30 |
return render(
|
| 31 |
request,
|
| 32 |
"quizzes/display.html",
|