我正在寻找一种方法来测试名为
fetch_options
的函数,该函数基本上呈现从内部 API 返回的 JSONResponse。我的测试方法是模拟 requests
,因为内部 API 位于另一个应用程序中,该应用程序已经在不同的测试套件中进行了测试。
我有一种直觉,该函数已通过模拟正确修补,但由于某种原因,我的
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
计划者/测试/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
,其中包含一个元素 — response [requests-docs],位于 list(response)
。如果field
==
"ingredients"
,index
==
1。现在看到错误了吗?当索引包含索引 1处的一个元素的
list
时,会引发 IndexError
异常。
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()
,后者将对 Context
数据进行一些 HTML 渲染。我建议这样做是因为我意识到您不需要 HTML 渲染,因为您要检查的只是 status_code
in:
self.assertContains(
fetch_options("request", "breakfast", "ingredients"), status_code=200
)