Невозможно отправить 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 остается прежним

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