def test_answer_many_incorrect_questions_many_topics(self): """ check that answering many incorrect questions affects competency children""" author_course = self._bootstrap_courses(1) author_user = self._bootstrap_user(1) author = CourseUser.objects.create(user=author_user, course=author_course) self._bootstrap_topics(author_course) topic_selected = Topic.objects.all().filter(id__in=[1, 2]) self._bootstrap_questions_same_topics(author, topic_selected, 20) self._bootstrap_question_choices(correct_id=2) QuestionService.respond_to_question(3, author) for i in range(1, 20): offset = 4 * i first_old_competency = Competency.objects.all()[0].competency second_old_competency = Competency.objects.all()[1].competency third_old_competency = Competency.objects.all()[2].competency QuestionService.respond_to_question(3 + offset, author) first_new_competency = Competency.objects.all()[0].competency second_new_competency = Competency.objects.all()[1].competency third_new_competency = Competency.objects.all()[2].competency self.assertTrue(first_old_competency >= first_new_competency) self.assertTrue(second_old_competency >= second_new_competency) self.assertTrue(third_old_competency >= third_new_competency) self.assertEqual(QuestionResponse.objects.count(), 20) num_topics = combinations( QuestionScore.objects.all().first().question.topics.all()) self.assertEqual(Competency.objects.count(), len(num_topics))
def test_decay_function(self): """ Test decay function influences question competency over time """ author_course = self._bootstrap_courses(1) author_user = self._bootstrap_user(1) responder_user = self._bootstrap_user(2) responder = CourseUser.objects.create(user=responder_user, course=author_course) author = CourseUser.objects.create(user=author_user, course=author_course) self._bootstrap_topics(author_course) topic_selected = Topic.objects.all().filter(id__in=[1]) self._bootstrap_questions_same_topics(author, topic_selected, 20) self._bootstrap_question_choices(correct_id=2) for question in Question.objects.all(): question.difficulty = 10 question.save() for i in range(0, 10): offset = 4 * i QuestionService.respond_to_question(2 + offset, author) QuestionService.respond_to_question(3 + offset, responder) for i in range(10, 20): offset = 4 * i QuestionService.respond_to_question(3 + offset, author) QuestionService.respond_to_question(2 + offset, responder) author_competency = Competency.objects.get(user=author).competency responder_competency = Competency.objects.get( user=responder).competency self.assertEqual(QuestionResponse.objects.count(), 40) self.assertEqual(QuestionScore.objects.count(), 40) self.assertTrue(author_competency <= responder_competency)
def make_question_responses(user, correct, incorrect, ability): if chance(2): user_choice = choose_answer(correct, incorrect, ability) response = QuestionService.respond_to_question(user_choice.id, user) if chance(2): rating = QuestionRating(quality=randrange(0, 10), difficulty=randrange(0, 10), response=user_choice, user=user) rating.save()
def test_add_filter_unanswered(self): """Test that questions are filtered when they have not been answered before, no QuestionResponse""" course = self._bootstrap_courses(1) user = self._bootstrap_user(1) author = CourseUser.objects.create(user=user, course=course) self._bootstrap_topics(course) self._bootstrap_questions(author) self._bootstrap_question_choices(correct_id=2) #answer the first two questions QuestionService.respond_to_question(2, author) QuestionService.respond_to_question(6, author) test_search = SearchService.SearchService(course) test_search.add_filter("unanswered", author) unanswered_questions = test_search.execute() # Check searched questions should be the last 3 unanaswered ones for i in unanswered_questions: self.assertTrue(i in Question.objects.all()[2:5]) self.assertEqual(test_search.execute().count(), 3)
def test_add_filter_answered(self): """test that questions can be filtered if they have been answered before, QuestionResponse exists""" course = self._bootstrap_courses(1) user = self._bootstrap_user(1) author = CourseUser.objects.create(user=user, course=course) self._bootstrap_topics(course) self._bootstrap_questions(author) self._bootstrap_question_choices(correct_id=2) #answer the first two questions QuestionService.respond_to_question(2, author) QuestionService.respond_to_question(6, author) test_search = SearchService.SearchService(course) test_search.add_filter("answered", author) answered_questions = test_search.execute() # Check searched questions should be the first 2 answered ones for i in answered_questions: self.assertTrue(i in Question.objects.all()[0:2]) self.assertEqual(test_search.execute().count(), 2)
def test_answer_many_correct_questions_single_topic(self): """ checks that answering many correct questions bring competency upwards""" author_course = self._bootstrap_courses(1) author_user = self._bootstrap_user(1) author = CourseUser.objects.create(user=author_user, course=author_course) self._bootstrap_topics(author_course) topic_selected = Topic.objects.all().filter(id__in=[1]) self._bootstrap_questions_same_topics(author, topic_selected, 20) self._bootstrap_question_choices(correct_id=2) QuestionService.respond_to_question(2, author) for i in range(1, 20): offset = 4 * i old_competency = Competency.objects.all().first().competency QuestionService.respond_to_question(2 + offset, author) new_competency = Competency.objects.all().first().competency self.assertTrue(old_competency <= new_competency) self.assertEqual(QuestionResponse.objects.count(), 20) self.assertEqual(Competency.objects.count(), 1)
def test_add_filter_improve(self): """ Test that questions can be filtered by questions answered where user did not get maximun score. QuestionResponse exists but Question Score < 1 """ course = self._bootstrap_courses(1) user = self._bootstrap_user(1) author = CourseUser.objects.create(user=user, course=course) self._bootstrap_topics(course) self._bootstrap_questions(author) self._bootstrap_question_choices(correct_id=2) #answer the first question correctly after two tries QuestionService.respond_to_question(3, author) QuestionService.respond_to_question(2, author) test_search = SearchService.SearchService(course) test_search.add_filter("improve", author) improve_questions = test_search.execute() self.assertEqual(Question.objects.all().first(), improve_questions.first()) self.assertEqual(test_search.execute().count(), 1)
def test_answer_question_different_difficulties(self): """ Test for checking that difficulty influences competency scores """ author_course = self._bootstrap_courses(1) author_user = self._bootstrap_user(1) responder_user = self._bootstrap_user(2) responder = CourseUser.objects.create(user=responder_user, course=author_course) author = CourseUser.objects.create(user=author_user, course=author_course) self._bootstrap_topics(author_course) topic_selected = Topic.objects.all().filter(id__in=[1]) self._bootstrap_questions_same_topics(author, topic_selected, 20) for question in Question.objects.all(): question.difficulty = 10 question.save() topic_selected = Topic.objects.all().filter(id__in=[2]) self._bootstrap_questions_same_topics(author, topic_selected, 20) self._bootstrap_question_choices(correct_id=2) starting_point = 20 * 4 QuestionService.respond_to_question(2, author) QuestionService.respond_to_question(2 + starting_point, responder) for i in range(1, 20): offset = 4 * i author_old_competency = Competency.objects.get( user=author).competency responder_old_competency = Competency.objects.get( user=responder).competency QuestionService.respond_to_question(2 + offset, author) QuestionService.respond_to_question((2 + starting_point) + offset, responder) author_new_competency = Competency.objects.get( user=author).competency responder_new_competency = Competency.objects.get( user=responder).competency self.assertTrue(author_old_competency <= author_new_competency) self.assertTrue( responder_old_competency <= responder_new_competency) self.assertTrue(author_new_competency >= responder_new_competency)
def respond(request): if request.method != 'POST': return JsonResponse({ "error": "Must use POST to this endpoint" }, status=405) post_request = loads(request.body) distractor_id = post_request.get("distractorID", None) if distractor_id is None: return JsonResponse({"error": "Missing integer distractorID in request"}, status=422) if QuestionService.respond_to_question(distractor_id, UserService.logged_in_user(request)) is None: return JsonResponse({"error": "Invalid distractorID"}, status=422) else: return HttpResponse(status=204)
def respond(request): if request.method != 'POST': return JsonResponse({ "error": "Must use POST to this endpoint" }, status=405) post_request = loads(request.body.decode("utf-8")) distractor_id = post_request.get("distractorID", None) try: if distractor_id is None: return JsonResponse({"error": "Missing integer distractorID in request"}, status=422) if QuestionService.respond_to_question(distractor_id, UserService.logged_in_user(request)) is False: return JsonResponse({"error": "Invalid distractorID"}, status=422) else: return JsonResponse({}) except ValueError: return JsonResponse({"error": "You are not enrolled in the course for this course"}, status=403)
def test_answer_alternating_questions_many_topics(self): """ answer alternating questions to ensure competency scores bounce accordingly """ author_course = self._bootstrap_courses(1) author_user = self._bootstrap_user(1) author = CourseUser.objects.create(user=author_user, course=author_course) self._bootstrap_topics(author_course) topic_selected = Topic.objects.all().filter(id__in=[1, 2]) self._bootstrap_questions_same_topics(author, topic_selected, 20) self._bootstrap_question_choices(correct_id=2) # Get question wrong QuestionService.respond_to_question(2, author) for i in range(1, 10): offset = (4 * i) + (4 * (i - 1)) first_old_competency = Competency.objects.all()[0].competency second_old_competency = Competency.objects.all()[1].competency third_old_competency = Competency.objects.all()[2].competency # Get question wrong QuestionService.respond_to_question(3 + offset, author) first_new_competency = Competency.objects.all()[0].competency second_new_competency = Competency.objects.all()[1].competency third_new_competency = Competency.objects.all()[2].competency self.assertTrue(first_old_competency >= first_new_competency) self.assertTrue(second_old_competency >= second_new_competency) self.assertTrue(third_old_competency >= third_new_competency) QuestionService.respond_to_question(2 + offset, author) self.assertTrue( first_new_competency <= Competency.objects.all()[0].competency) self.assertTrue( second_new_competency <= Competency.objects.all()[1].competency ) self.assertTrue( third_new_competency <= Competency.objects.all()[2].competency) self.assertEqual(QuestionResponse.objects.count(), 19) num_topics = combinations( QuestionScore.objects.all().first().question.topics.all()) self.assertEqual(Competency.objects.count(), len(num_topics))
def test_sorting_responses_ascending(self): """Check that the questions get sorted by their number of responses in ascending order """ course = self._bootstrap_courses(1) user = self._bootstrap_user(1) author = CourseUser.objects.create(user=user, course=course) responder_user = self._bootstrap_user(2) first_responder = CourseUser.objects.create(user=responder_user, course=course) another_responder_user = self._bootstrap_user(3) second_responder = CourseUser.objects.create( user=another_responder_user, course=course) self._bootstrap_topics(course) self._bootstrap_questions(author) self._bootstrap_question_choices(correct_id=2) #First question is responded 3 times, started from the back to ensure descending sorting happens QuestionService.respond_to_question(1, author) QuestionService.respond_to_question(2, first_responder) QuestionService.respond_to_question(3, second_responder) #Second question is responded two times QuestionService.respond_to_question(5, author) QuestionService.respond_to_question(6, first_responder) #Third question is responded once QuestionService.respond_to_question(9, author) test_search = SearchService.SearchService(course) #The sorting order does not matter as anything that is not DESC will be considered ascending test_search.add_sort("responses", "ASC", author) sorted_questions = test_search.execute() for i in range(0, sorted_questions.count() - 1): responses = QuestionResponse.objects.filter( response__in=Distractor.objects.filter( question=Question.objects.get(id=sorted_questions[i].id))) next_responses = QuestionResponse.objects.filter( response__in=Distractor.objects.filter( question=Question.objects.get(id=sorted_questions[i + 1].id))) self.assertTrue(responses.count() <= next_responses.count())