Единичное тестирование Django JSON View

Я пытаюсь написать некоторые модульные тесты для некоторых представлений Django json_view, и мне не удается передать json_string в представление. Вчера я опубликовал связанный с этим вопрос о передаче строки json в представление Django из JS, проблема заключалась в том, что в моем JS я просто передавал строку json, где мне нужно было передавать строку как атрибут объекта, потому что я не выполнял этого, строка принималась за ключ для результирующего запроса dict. У меня возникла аналогичная проблема, за исключением того, что на этот раз это Django unit test для Django View. Вот упрощенная версия моего кода, которая дает тот же результат.

class MyTestCase(TestCase):
    def setUp(self):
        self.u = User.objects.create_user('test','test','test')
        self.u.is_active = True
        self.u.save()
        self.client.login(username='test',password='test')

    def test_create_object_from_form(self):
        """Test the creation of the Instance from the form data."""
        import json
        json_string json.dumps({'resource':{'type':'book','author':'John Doe'}})
        print(json_string)
        response = self.client.post(reverse('ajax_view'),
                                    {'form':json_string},'json')
        self.assetNotContains(response,'error')

и вид выглядит следующим образом

@json_view
def ajax_view(request):
    """Process the incoming form data."""
    if request.method == 'POST':
        print(request.POST)
        form_data = json.loads(request.POST['form'])
        resource_data = form_data['resource']
        form = MyUserForm(resource_data)

        if form.is_valid():
        ...

Вот что производят два оператора печати при запуске теста. Json_string

{"resource": {"type": "book", "author": "John Doe"}}

и запрос dict выглядит как

<QueryDict: {u'{\'form\': \'{"resource": {"type": "book", "author": "John Doe"}}\'}': [u'']}>

Я полный новичок с JS и ajax, так что не беспокойтесь о том, чтобы повредить мою гордость, ответ, вероятно, так близко, что он может вскочить и укусить меня.

Ответ 1

Окончательное редактирование

Я изначально заявил, что заголовок HTTP_X_REQUESTED_WITH='XMLHttpRequest' был необходим в пост-вызове, но в настоящее время он является ложным во время тестов. Этот заголовок необходим для промежуточного программного обеспечения csrf, но csrf отключен в тестах. Тем не менее, я по-прежнему считаю, что хорошей практикой является тестирование, даже если middleware отключает csrf, поскольку большинство javascript-библиотек уже передают этот заголовок по умолчанию при выполнении ajax. Кроме того, если другой фрагмент кода, который не отключен, когда-либо использовал метод is_ajax, вам не нужно будет отлаживать ваш unittest в течение нескольких часов, чтобы понять, что заголовок отсутствует.

Проблема связана с типом контента, потому что, когда django получает там значение, отличное от text/html, оно не использует обработку сообщений по умолчанию, которая предназначена для форматирования ваших данных, как в запросе: type=book&author=JohnDoe например.

Тогда фиксированный код:

response = self.client.post(reverse('ajax_view'),
                            {'form':json_string}, 
                            HTTP_X_REQUESTED_WITH='XMLHttpRequest')

Вот как я сам его использую:

post_data = { 
    "jsonrpc" : "2.0", "method": method, "params" : params, "id" : id }
return client.post('/api/json/', 
                    json.dumps(post_data), "text/json",            
                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')

сделать json-rpc. Обратите внимание, что, поскольку я передаю другой тип контента, чем значение по умолчанию, мои данные передаются как есть в сообщении.

Ответ 2

Спасибо @Eric_Fortin за то, что я включил его в заголовок, однако он не разрешает мою проблему с искаженным поисковым словарем, используя "client.post". Как только я внес изменения из POST в GET с заголовком XMLHttpRequest, мой запросный словарь стеснялся. Вот текущее решение:

response = self.client.get(reverse('ajax_view'),
                           {'form':json_string},'json',
                           HTTP_X_REQUESTED_WITH='XMLHttpRequest')

это лишь частичный ответ, так как этот запрос будет изменять данные на сервере и должен быть POST не GET.

Edit:

Вот последний код в моем тесте, который работает для передачи строки JSON через POST на мой взгляд:

response = self.client.post(reverse('ajax_view'),
                            {'form':json.dumps(json_dict)})

Теперь печать из представления показывает, что словарь запросов хорошо сформирован.

<QueryDict: {u'form': [u'{"resource": {"status": "reviewed", "name": "Resource Test", "description": "Unit Test"}}']}>

Я нашел ответ, возившись с одним из моих сотрудников, удалив content_type 'json' исправленный неверный словарь словаря. Проверяемое представление не использует или не вызывает "HttpRequest.is_ajax()", отправка заголовка XMLHttpRequest "не влияет на мою проблему", хотя включение заголовка будет хорошим, поскольку этот пост является запросом ajax.