Я пытаюсь протестировать конечные точки для своего API, используя это руководство. В частности, этот блок должен проверять запрос на получение:
class GetAllPuppiesTest(TestCase):
""" Test module for GET all puppies API """
def setUp(self):
Puppy.objects.create(
name='Casper', age=3, breed='Bull Dog', color='Black')
Puppy.objects.create(
name='Muffin', age=1, breed='Gradane', color='Brown')
Puppy.objects.create(
name='Rambo', age=2, breed='Labrador', color='Black')
Puppy.objects.create(
name='Ricky', age=6, breed='Labrador', color='Brown')
def test_get_all_puppies(self):
# get API response
response = client.get(reverse('get_post_puppies'))
# get data from db
puppies = Puppy.objects.all()
serializer = PuppySerializer(puppies, many=True)
self.assertEqual(response.data, serializer.data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
Когда я пытаюсь адаптировать это к своему собственному тесту, это выглядит так:
from ..models import DemanderFeature, DemanderFeatureCollection
from rest_framework import status
from django.test import TestCase, Client
from django.urls import reverse
from ..serializers import DemanderFeatureCollectionSerializer
class GetAllDemanderFeatureCollections(TestCase):
def setUp(self):
DemanderFeatureCollection.objects.create(name='testdemanderfeaturecollection0')
DemanderFeatureCollection.objects.create(name='testdemanderfeaturecollection1')
def test_get_all_demandercollections(self):
# get API response
response = client.get(reverse('demandercollections-list'))
# get data from db
demanderfeaturecollections = DemanderFeatureCollection.objects.all()
serializer = DemanderFeatureCollectionSerializer(demanderfeaturecollections, many=True)
self.assertEqual(response.data, serializer.data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
Однако проблема заключается в том, что метод reverse()
возвращает только относительный URL-адрес (/demandercollections/
), а затем client.get(reverse(...))
возвращает 404. Я не понимаю, как заставить его использовать фактический явный URL-адрес во время тестирования.
Я использую Джанго 3.
Мой основной urls.py выглядит так:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("app.urls")),
path('api-auth/', include('rest_framework.urls')),
]
И мой модуль urls.py выглядит так:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from app import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'demanders', views.DemanderFeatureViewSet)
router.register(r'demandercollections', views.DemanderFeatureCollectionViewSet, basename = "demandercollections")
router.register(r'producers', views.ProducerFeatureViewSet)
router.register(r'producercollections', views.ProducerFeatureCollectionViewSet)
router.register(r'pathfinderrunconfigurations', views.PathfinderRunConfigurationViewSet)
router.register(r'users', views.UserViewSet)
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
DemanderCollectionViewSet
в views.py выглядит так:
class DemanderFeatureCollectionViewSet(
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet
):
queryset = DemanderFeatureCollection.objects.all()
serializer_class = DemanderFeatureCollectionSerializer
lookup_field = 'name'
@action(detail=True, methods=["get"])
def geojson(self, request, *args, **kwargs):
demanders = DemanderFeature.objects.filter(demandercollection=self.get_object())
return Response(serialize('geojson', demanders, geometry_field='geom', fields=('name',)))
@action(detail=True, methods=["patch"])
def commit(self, request, *args, **kwargs):
demandercollection = self.get_object()
if not request.data["committed"]:
# User is trying to "uncommit", do not allow this
return Response("You may not un-commit a DemanderCollection. You must copy it and make modifications on the copy.", status=status.HTTP_400_BAD_REQUEST)
demandercollection.committed = True
demandercollection.save()
return Response(status=status.HTTP_204_NO_CONTENT)
def get_queryset(self):
user = get_object_or_404(User, username=self.request.user)
return DemanderFeatureCollection.objects.filter(deleted=False).filter(owner=user).order_by("name")
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def destroy(self, request, *args, **kwargs):
demandercollection = self.get_object()
demandercollection.deleted = True
demandercollection.save()
return Response(f"Successfully deleted DemanderCollection.")
Мало того, что принятый ответ действительно был виновником, но он также показал, что создаваемые объекты DemanderFeatureCollection
также должны быть созданы с атрибутом owner
, а объект client
должен вызывать свой метод login()
для действительной пары учетных данных пользователя.
Поэтому тестовый класс пришлось обновить, чтобы он выглядел следующим образом:
class GetAllDemanderFeatureCollections(TestCase):
""" Test module for GET all puppies API """
def setUp(self):
self.test_user = User.objects.create_user('test_user', '[email protected]', 'test_user')
self.other_user = User.objects.create_user('other_user', '[email protected]', 'other_user')
client.login(username = "test_user", password = "test_user")
DemanderFeatureCollection.objects.create(name='testdemanderfeaturecollection0', owner=self.test_user)
DemanderFeatureCollection.objects.create(name='testdemanderfeaturecollection1', owner=self.test_user)
DemanderFeatureCollection.objects.create(name='otherdemanderfeaturecollection0', owner=self.other_user)
def test_get_all_demandercollections_for_user(self):
# get API response
response = client.get(reverse('demandercollections-list'))
# get data from db
demanderfeaturecollections = DemanderFeatureCollection.objects.filter(owner=self.test_user).all()
serializer = DemanderFeatureCollectionSerializer(demanderfeaturecollections, many=True)
self.assertEqual(response.data, serializer.data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
Я добавил оператор импорта для reverse()
в тестовый блок кода, а также источник DemanderFeatureCollectionViewSet
при базовой проверке я вижу, что вы фильтруете get_queryset()
с некоторым полем owner
, и это может быть причиной ошибки 404.
Похоже, в этом была суть вопроса. Я не только не регистрировался в качестве тестового пользователя, но и объекты DemanderFeatureCollection
создавались без связанного пользователя в качестве владельца (кажется, я все еще разрешал создавать бесхозные объекты модели DemanderFeatureCollection
, что также является проблемой). Я создал тестового пользователя в методе setUp()
и вошел в него через client.login()
в методе test_get_all_demandercollections()
. Тогда это сработало как исключение. Если вы хотите сделать свой комментарий ответом, я приму его.
В методе get_queryset()
класса DemanderFeatureCollectionViewSet
вы фильтруете экземпляры модели с полем owner
по вошедшему в систему пользователю.
В ваших тестовых примерах вы создаете экземпляры DemanderFeatureCollection
без привязки user
и, следовательно, DRF вызывает ошибку HTTP 404. Таким образом, присоединение пользователя к экземпляру и выполнение запроса с тем же пользователем даст вам правильный ответ от API.
Добавьте свой класс
DemanderFeatureCollectionViewSet
, а также ссылку на функциюreverse()
, которую вы использовали (дело в том, что есть дваreverse()
удовольствия)