Как издеваться над Django queryset, который был получен из related_name?
Я хочу провести unittest этой функции, которая является service-function внутри моего приложения Django:
from datetime import date, timedelta
from account.models import Profile
from lesson.models import Lesson, Question
from repeat.models import RepetitionSession
class QuestionService:
@staticmethod
def get_next_question_by_rep_session(rep_session: RepetitionSession) -> Question:
today_date = date.today()
questions_filter = rep_session.questions.filter(next_repeat_at=today_date)
sorted_questions_filter = questions_filter.order_by('edited_at')
next_question = sorted_questions_filter.first()
return next_question
Это было так, но я разделил это на 3 строки:
next_question = rep_session.questions.filter(next_repeat_at=today_date).order_by('edited_at').first()
Вот мой unittest:
from datetime import date, timedelta
from random import randint
from unittest.mock import patch, MagicMock
from django.test import SimpleTestCase
from lesson.services import QuestionService
class QuestionServicesTest(SimpleTestCase):
FILE_PATH = 'lesson.services.question_service'
def test_get_next_question_by_rep_session(self):
test_query = MagicMock()
test_question = MagicMock()
test_rep_session = MagicMock()
test_rep_session.questions = test_query
test_query.filter().return_value = test_query
test_query.order_by().return_value = test_query
test_query.first().return_value = test_question
result = QuestionService.get_next_question_by_rep_session(test_rep_session)
test_query.filter().assert_called_once_with(next_repeat_at=date.today())
Я получаю этот отказ https://i.stack.imgur.com/85Dzl.png
AssertionError: Ожидалось, что 'mock' будет вызван один раз. Вызывается 0 раз. Вызовы: [call.order_by('edited_at'), call.order_by().first()].
Итак, если я хочу протестировать filter(), я обычно делаю следующее:
@patch(f'{FILE_PATH}.Model_name.objects.filter')
def test_example_func(self, patch_filter):
test_attr = MagickMock()
test_query = MagickMock()
patch_filter.return_value = test_query
result = example_func(test_attr)
patch_filter.assert_called_once_with(test_attr)
Пожалуйста, помогите мне найти то, что я пропустил.
Я понял свою ошибку. Посмотрим изменения:
def test_get_next_question_by_rep_session(self):
test_query = MagicMock()
expected_question = MagicMock()
fail_question = MagicMock()
test_rep_session = MagicMock()
test_rep_session.questions = test_query
test_query.filter.return_value = test_query # Mistake was here
test_query.order_by.return_value = test_query # Mistake was here
test_query.first.return_value = expected_question # Mistake was here
result = QuestionService.get_next_question_by_rep_session(test_rep_session)
test_query.filter.assert_called_once_with(next_repeat_at=date.today()) # Mistake was here
test_query.order_by.assert_called_once_with('edited_at')
test_query.first.assert_called_once()
self.assertEqual(result, expected_question)
self.assertNotEqual(result, fail_question)
Итак, когда мы подражаем объектам, это работает следующим образом:
x.return_value = 420
# When we will call x we will get 420
>>> x()
>>> 420
def x() -> y:
...
x().return_value = 665
# However when we will call result of the x() we will get 665
>>> y
>>> 665
Если я где-то ошибся, пожалуйста, сообщите мне об этом.