Почему тест django-rest-framework возвращает другой ответ, чем идентичное сообщение через postman?
Контекст:
В настоящее время я переписываю свою реализацию django-rest-framework для использования пользовательского класса разрешений. В процессе я пишу тесты, чтобы убедиться, что любые будущие изменения ничего не сломают.
Связанные объекты:
View
Serializer
Симптомы:
Я выполняю следующий тест:
def test_event_edit_authenticated_non_org_user(self):
'''test that an event can be edited by an non-org user'''
#self.client.force_authenticate(user=self.user1)
response = self.client.post(
'/backend/api/event/',
{
'name': 'Test Event',
'content': 'This is a test event',
'start': '2020-01-01T00:00:00Z',
'end': '2020-01-01T01:00:00Z',
'organizationChange': self.org1.short_name,
'location': 'Test Location',
},
HTTP_AUTHORIZATION='Token ' + self.token1.key,
format='json'
)
self.assertEqual(response.status_code, 201)
event = Event.objects.get(uuid=response.data['uuid'])
#self.client.force_authenticate(user=self.user2)
response = self.client.patch(
'/backend/api/event/' + str(event.uuid) + '/',
{'uuid': str(event.uuid),
'name': 'Test Event 2',
'content': 'This is a test event',
'start': '2020-01-01T00:00:00Z',
'end': '2020-01-01T01:00:00Z',
'location': 'Test Location',
},
HTTP_AUTHORIZATION='Token ' + self.token2.key,
format='json'
)
self.assertEqual(response.status_code, 403)
Я получаю эту ошибку:
======================================================================
ERROR: test_event_edit_authenticated_non_org_user (events.tests.EventTest.test_event_edit_authenticated_non_org_user)
test that an event can be edited by an non-org user
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\env\scorg\django\events\tests.py", line 232, in test_event_edit_authenticated_non_org_user
event = Event.objects.get(uuid=response.data['uuid'])
~~~~~~~~~~~~~^^^^^^^^
KeyError: 'uuid'
У меня аналогичная ошибка во всех моих тестах, которые требуют uuid как часть данных ответа.
Что я пробовал
1. Я проверил, что поле 'uuid' не возвращается, распечатав ответ.
Response for event creation: {'name': 'Test Event', 'source': None, 'discord_event_id': None, 'my_interest': False, 'organization': None, 'content': 'This is a test event', 'start': '2020-01-01T00:00:00Z', 'end': '2020-01-01T01:00:00Z', 'location': 'Test Location', 'discord_link': None, 'discord_description': None, 'discord_location': None, 'interested': None, 'jobs': None, 'canRead': True, 'canWrite': False, 'canEdit': False, 'canDelete': False}
Это подтвердило, что поле uuid не возвращается.
2. Я проверил, что 'uuid' включен в соответствующий сериализатор:
lass EventSerializer(serializers.ModelSerializer):
...
class Meta:
model = Event
fields = ['uuid','name','source','discord_event_id','my_interest','organization','short_name','content','owner','type','start','end','location','discord_link','discord_event_id','discord_description','discord_location','status','created','interested','jobs','canRead','canWrite','canEdit','canDelete']
...
Это подтвердило, что поле 'uuid' включено в соответствующий сериализатор.
3. Я создал ручную почту с помощью Postman, чтобы проверить, имеет ли ручная почта такую же проблему.
POST запрос:
{
"name": "Test Event2",
"content": "This is a test event",
"start": "2020-01-01T00:00:00Z",
"end": "2020-01-01T01:00:00Z",
"organizationChange": "ESHORES",
"location": "Test Location"
}
Ответ:
{
"uuid": "7f7568b0-a07c-441d-915d-9ab3d3619a01",
"name": "Test Event2",
"source": "scorg",
"discord_event_id": null,
"my_interest": false,
"organization": {
"uuid": "6fcec5b4-b2b4-49ea-bcb4-93ff585670e4",
"name": "ESHORES",
"short_name": "ESHORES",
"url": "https://robertsspaceindustries.com/orgs/ESHORES/"
},
"short_name": "ESHORES",
"content": "This is a test event",
"owner": 231574499013820417,
"type": 0,
"start": "2020-01-01T00:00:00Z",
"end": "2020-01-01T01:00:00Z",
"location": "Test Location",
"discord_link": null,
"discord_description": null,
"discord_location": null,
"status": 0,
"created": "2023-01-11T20:07:02.783395Z",
"interested": null,
"jobs": [],
"canRead": true,
"canWrite": true,
"canEdit": true,
"canDelete": true
}
Очевидно, что он правильно возвращает uuid.
4. Я искал в google/stack/reddit и даже спрашивал chatGPT безрезультатно.
Я ожидал, что почта тестового клиента и почта ручного почтальона будут возвращать одинаковые поля, однако тестовый клиент этого не делает. Есть ли у кого-нибудь идеи, почему?
Поскольку вы вручную вставляете 'uuid'
в validated_data
, он не будет находиться в response.data
. Если вы хотите подтвердить фактический возвращаемый вывод, вам нужно проверить необработанный response.content
:
data = json.loads(response.content)
uuid = data['uuid']
Это фактическое тело ответа, которое было возвращено из конечной точки.
def test_event_edit_authenticated_non_org_user(self):
'''test that an event can be edited by an non-org user'''
#self.client.force_authenticate(user=self.user1)
response = self.client.post(
'/backend/api/event/',
{
'uuid': '79576b8d-2225-42a7-be58-9b61033cbea7',
'name': 'Test Event',
'content': 'This is a test event',
'start': '2020-01-01T00:00:00Z',
'end': '2020-01-01T01:00:00Z',
'organizationChange': self.org1.short_name,
'location': 'Test Location',
},
HTTP_AUTHORIZATION='Token ' + self.token1.key,
format='json'
)
self.assertEqual(response.status_code, 201)
event = Event.objects.last()
Вам придется указать UUID вручную Теперь вы будете использовать переменную события для получения всех полей модели событий
Пройдя через логику, я обнаружил, что в проверке разрешений была допущена ошибка. Я делал это слишком рано и не включил параметр. Я не могу объяснить, почему это работало на postman, но не на моих тестах, но изменение следующих параметров устранило ошибку:
def perform_create(self, serializer):
user = self.request.user
org = None
# check if user has necessary permissions to create events
if 'organizationChange' in self.request.data:
try:
org = Organization.objects.get(short_name=self.request.data['organizationChange'])
except:
print('Organization does not exist')
pass
elif 'guild' in self.request.data:
try:
org = DiscordServer.objects.get(server_id=self.context['request'].data['guild']).org
except:
pass
perm = CheckPermission(capability='event', org=org, action='create').has_permission(self.request, self)
Я переместил perm = CheckPermission() с верхнего уровня логики 'if organizationChange' на нижний, и это решило проблему. uuid не передавался, потому что объект не был успешно создан.