Переменная сеанса, установленная перед запросом, недоступна в представлении Django во время тестов - PullRequest
0 голосов
/ 08 марта 2020

Мне нужно хранить некое состояние между HTTP-запросами. Поскольку я не использую интерфейс JS, я решил использовать переменные сеанса, хранящиеся в файлах cookie. Мои настройки сеанса выглядят следующим образом:

SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
SESSION_COOKIE_HTTPONLY = False

Мне нужна функция, чтобы легко манипулировать одной переменной сеанса. Поскольку эта функция довольно проста, я решил использовать исключительно функциональное представление:

def set_category_filter(request, pk):
    if pk == 0:
        if 'filter_category_id' in request.session:  # this is False during unit testing, but it's ok in a normal app run
            del request.session['filter_category_id']
    else:
        get_object_or_404(Category, pk=pk, user=request.user)
        request.session['filter_category_id'] = pk
    return redirect('index')

Проблема в том, что я не могу выполнить тестовый случай, когда хочу сбросить эту переменную сеанса. Предположим, переменная сеанса filter_category_id установлена, и я хочу сбросить ее. Когда я делаю это в своем браузере, все работает хорошо. Когда я пытаюсь сделать это через Django TestCase, происходит сбой, потому что эта переменная сеанса не передается в запрос!

class SetCategoryFilterTest(TestCase):
    def setUp(self) -> None:
        super().setUp()
        self.fake = Faker()
        self.user = User.objects.create_user(username="testuser", password="12345")
        self.client.force_login(self.user)

    def tearDown(self):
        self.client.logout()

    # ...

    def test_unset_successfully(self):
        """Werify unsetting "filter_category_id" session field.

        Expected: Delete "filter_category_id" when url called with parameter 0
        """

        # GIVEN
        session = self.client.session
        session['filter_category_id'] = DUMMY_INT
        session.save()

        clear_arg = 0

        # WHEN
        self.client.get(reverse("filter_tasks_by_category", args=[clear_arg]))

        # THEN
        self.assertFalse("filter_category_id" in session)

Как вы видите, я пытаюсь предположить в тесте, что упомянутый сеанс переменная уже установлена. Затем я пытаюсь удалить, но есть две проблемы:

  1. Во время отладки условие if 'filter_category_id' in request.session равно False, поэтому переменная сеанса не сбрасывается.

  2. После того, как запрос выполнен и выполнение кода возвращается к тестовому сценарию, переменная сеанса, установленная в начале тестового примера, все еще существует, поэтому тест не пройден.

Я пытался следовать правилу из документации , что нам нужно сохранить сеанс в переменной до изменения и вызвать save() после. Но это не помогло. Кроме того, я где-то читал, что лучше сделать еще один запрос или хотя бы login(), чтобы установить объект сеанса. Но, как вы видите в методе setUp(), вход в систему уже выполнен.

Это также не помогает, когда я пытаюсь выполнить другой запрос к , гарантирующему , что сеанс был создан:

def test_unset_successfully(self):
    """Werify unsetting "filter_category_id" session field.

    Expected: Delete "filter_category_id" when url called with parameter 0
    """

    # GIVEN
    category = Category.objects.create(user=self.user, name=self.fake.name())
    self.client.get(reverse("filter_tasks_by_category", args=[category.id]))

    session = self.client.session
    session['filter_category_id'] = DUMMY_INT
    session.save()

    clear_arg = 0

    # WHEN
    self.client.get(reverse("filter_tasks_by_category", args=[clear_arg]))

    # THEN
    self.assertFalse("filter_category_id" in session)

Этот код не только странный, но и не подтверждает утверждение о том, что мне нужно сначала сделать запрос перед доступом к объекту сеанса.

Знаете ли вы, как справиться с этой ситуацией? По сути, все, что я хочу сделать, - это установить переменную сеанса и передать ее с запросом на мой взгляд.

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Если вы хотите просто протестировать удаляемую часть, используйте mocks:

def test_unset_successfully(self):
    request_mock = Mock()
    request_mock.session = {"filter_category_id": 123}

    set_category_filter(request_mock, 0)

    self.assertIsNone(request_mock.session.get("filter_category_id"))
0 голосов
/ 25 марта 2020

Наконец-то я узнал, что мне нужно обновить сессию cook ie:

# GIVEN
session = self.client.session
session["filter_category_id"] = DUMMY_INT
session.save()

# After saving new session, it must be re-assigned to a session cookie
session_cookie_name = django_settings.SESSION_COOKIE_NAME
self.client.cookies[session_cookie_name] = session.session_key

Решение найдено на https://kurzacz.com/writing-django-tests-for-session-variables-stored-in-cookies/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...