Контекст ответа Django с использованием клиента pytest-django всегда равен None

Я использую pytest-django для тестирования некоторых представлений Django.

Я хочу проверить, что контекст ответа содержит определенные значения, но всегда None.

Мой взгляд:

from django.views.generic import TemplateView

class MyView(TemplateView):
    template_name = 'my_template.html'

    def get_context_data(self, **kwargs):
        context = super(MyView, self).get_context_data(**kwargs)
        context['hello'] = 'hi'
        return context

Мой тест:

def test_context(client):
    response = client.get('/test/')
    print('status', response.status_code)
    print('content', response.content)
    print('context', response.context)

Если я запускаю это с флагом -s, чтобы увидеть операторы печати, код состояния будет 200, а content будет содержать отображаемый шаблон, включая "hi", который находится в контексте. Но context это None.

Я думал, что это client было таким же, как django.test .Client, который должен позволить мне видеть контекст... так что же мне не хватает?

Я пробовал этот ответ, но получил

RuntimeError: setup_test_environment() уже был вызван и не может быть вызван снова без предварительного вызова teardown_test_environment().


person Phil Gyford    schedule 10.08.2017    source источник
comment
Вы создаете настройку с суперпользователем? Потому что иногда ваше приложение не нашло это. Не могли бы вы показать больше о своем классе Test и вашем urls.py, вместо этого используйте URL-адреса жесткого кода, попробуйте использовать from django.core.urlresolvers import reverse.   -  person Aipi    schedule 10.08.2017
comment
Нет, это общедоступная страница. Обычно я бы использовал reverse() в тестах и ​​попробовал это здесь с тем же эффектом, я просто максимально упростил ситуацию, чтобы попытаться найти проблему.   -  person Phil Gyford    schedule 10.08.2017
comment
Не могли бы вы добавить больше об этом тестовом коде?   -  person Aipi    schedule 10.08.2017
comment
Я не уверен, что ты хочешь увидеть. Я показал весь вид и весь тест.   -  person Phil Gyford    schedule 10.08.2017
comment
Вы можете попробовать использовать from django.test import TestCase и создать класс, который наследует this, а этот метод наследует test_context(self). Потому что, видимо, этот метод в порядке. Я не знаю, как вы передаете клиенту это.   -  person Aipi    schedule 10.08.2017
comment
Как уже говорилось, я использую pytest-django. Это не ванильный тест Джанго. Вот откуда client.   -  person Phil Gyford    schedule 10.08.2017
comment
У меня была похожая проблема, и я обнаружил, что сначала мне пришлось использовать client.login(), потому что для моего представления требовался аутентифицированный пользователь. Это не решение в вашем случае, потому что шаблон отображается, поэтому я создал небольшой проект Django, чтобы выяснить, в чем может быть проблема. Я использовал Python 3.7, Django 3.0, pytest 5.4.3 и pytest-django 3.9.0. По крайней мере, в этих версиях response.context['hello'] было "hi", как и ожидалось. Я могу предоставить код, если вы все еще заинтересованы.   -  person mcrot    schedule 18.06.2020


Ответы (1)


В предоставленной вами клиентской ссылке , указывает, что client является экземпляром django.test.Client так что на самом деле это не делает ничего особенного и не должно быть проблемой.

Вам нужно настроить среду, как вы правильно сказали.
Давайте теперь посмотрим на ошибку:

из исходного кода setup_test_environment():

if hasattr(_TestState, 'saved_data'):
      # Executing this function twice would overwrite the saved values.
      raise RuntimeError(
          "setup_test_environment() was already called and can't be called "
          "again without first calling teardown_test_environment()."
)

И это то, что поднимает ваш RuntimeError выше.

Теперь давайте посмотрим на метод teardown_test_environment():

...
del _TestState.saved_data

Таким образом, он удаляет виновника вышеупомянутого исключения.

Таким образом:

from django.test.utils import teardown_test_environment, setup_test_environment

try:
    # If setup_test_environment haven't been called previously this
    # will produce an AttributeError.
    teardown_test_environment()
except AttributeError:
    pass

setup_test_environment() 

...
person John Moutafis    schedule 11.08.2017
comment
Спасибо, Джон. Все это имеет смысл ... за исключением того, что когда я пытаюсь это сделать, строка saved_data = _TestState.saved_data в teardown_test_environment() генерирует AttributeError: объект типа '_TestState' не имеет атрибута 'saved_data'... - person Phil Gyford; 11.08.2017
comment
@PhilGyford Ну, кажется, работает в первый раз, но со второго раза возникает ошибка времени выполнения. Я внес правку и поместил teardown_test_environment на try-except block, где, если он выйдет из строя, он не уничтожит ваши тесты. - person John Moutafis; 11.08.2017
comment
Спасибо ... хотя теперь я вернулся к исходной ошибке RuntimeError, которую я получил в первую очередь. - person Phil Gyford; 11.08.2017
comment
@PhilGyford Можете ли вы поместить setup_test_environment в try-except block и сообщить мне о результате? - person John Moutafis; 11.08.2017
comment
Независимо от того, делаю я это или нет, я все равно получаю RuntimeError, но я только что понял, что он генерируется вызовом setup_test_environment в pytest_django/plugin.py здесь - person Phil Gyford; 12.08.2017
comment
если это вызывается, то вызов setup_test_environment становится дублирующим вызовом, попробуйте без вызова, оставьте только блок try: teardown_test_environment except - person John Moutafis; 12.08.2017
comment
Итак, он пытается выполнить teardown_test_environment, исключение которого теперь незаметно перехватывается, поэтому тест выполняется без ошибок... но контекст по-прежнему None, хотя этого быть не должно. - person Phil Gyford; 12.08.2017