Невозможно отправить json-ответ в запросах mock
Я ищу способ протестировать функцию fetch_options
, которая в основном отображает возвращаемый JSONResponse из внутреннего API. Мой подход к этому тесту заключается в подражании requests
, поскольку внутренний API находится в другом приложении, которое уже тестировалось в другом тестовом наборе.
У меня есть интуиция, что функция правильно пропатчена с помощью mock, но по какой-то причине мой вызов render
не может получить данные ответа, хотя я могу ошибаться.
planner/views/meals.py
def fetch_options(request, meal, field):
if field == "ingredients":
index = 1
else:
index = 0
try:
response = requests.get("log/api/send_" + field) #Trying to mock requests here, request fetches from /log/views/api.py
except ConnectionError:
requests.raise_from_exception()
else:
return render(request, {"meal": meal, "options": list(response)[index]}) # throws list index out range in tests
/log/views/api.py
def send_data(request, option):
match option:
case "ingredients":
data = Log.objects.first().recipe_ingredients
case "areas":
data = Log.objects.first().recipe_area
case "categories":
data = Log.objects.first().recipe_categories
case "activities":
data = Log.objects.first().activities
response = JsonResponse(data, status=200, safe=False)
return response
planner/tests/test_meals_view.py
from unittest import MagicMock, patch
@patch("planner.views.meals.requests")
def test_fetch_options(self, mock_requests):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json_data = [{"id": "357", "strIngredient": "Orange"}]
mock_requests.get.return_value = mock_response
self.assertContains(
fetch_options("request", "breakfast", "ingredients"), status_code=200
)
Может ли кто-нибудь сказать мне, что я упускаю или делаю неправильно, пожалуйста?
1. Вы создаете list
, содержащий один элемент - ответ [requests-docs]- в list(response)
. Если field
==
"ingredients"
, index
==
1. Теперь видите ошибку? При индексировании list
, содержащего один элемент с индексом 1, возникает исключение IndexError
.
2. Вспомогательная функция render()
[django-docs] не принимает сигнатуру функции, которую вы использовали:
render(request, {"meal": meal, "options": list(response)[index]})
Правильная подпись будет такой:
render(request, template_name, •••Rest of parameters•••)
Моей рекомендацией будет:
1. Сначала прочитайте Response
из requests.get()
и извлеките данные в виде JSON
или Text
.
response.json()
# OR
response.text
2. Рассмотрите возможность построения и возврата Django HttpResponse
непосредственно вместо использования render()
, что приведет к рендерингу HTML с данными Context
, переданными в render()
. Я предлагаю это, потому что понял, что вам не нужен HTML-рендеринг, поскольку все, что вы проверяете, это status_code
в:
self.assertContains(
fetch_options("request", "breakfast", "ingredients"), status_code=200
)
Ответ Chukwujiobi Canon дал мне важные указания для решения проблемы. Это были скорее ошибки в коде, которые я допустил из-за рассеянности (я работаю над этим проектом уже некоторое время)
planner/views/meals.py
def fetch_options(request, meal, field):
try:
response = requests.get("log/api/send_" + field)
except ConnectionError:
requests.raise_from_exception()
else:
data = response.json()
return render(
request,
"planner/edit_meal.html",
{"meal": meal, "options": data},
)
planner/tests/test_meals_view.py
@patch("planner.views.meals.requests")
def test_fetch_options(self, mock_requests):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = ["Orange", "Pineapple", "Watermelon"]
mock_requests.get.return_value = mock_response
self.assertContains(
fetch_options("request", "breakfast", "ingredients"),
"Orange",
status_code=200,
)
log/views/api.py
остается прежним