Как издеваться над 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

Если я где-то ошибся, пожалуйста, сообщите мне об этом.

Вернуться на верх