dimanche 23 août 2020

Django REST Framework Testing and Token Authentication

I have a REST API working and accessible via Postman with token authentication. I'm trying now to write tests for the API. This test case set up will work fine, though it returns a 401 status (as expected):

class ModelCRUDTests(TestCase):

    def setUp(self):
        self.thing = TestThingFactory.create()

        self.client = APIClient()

        self.response = self.client.get(
            reverse('appname:things-detail', kwargs={'pk': self.thing.pk}),
            )

When I add credentials, I get an error from the GET request (debugging shows that the authentication is stored in the client correctly). Modified code:

class ModelCRUDTests(TestCase):

    def setUp(self):
        self.thing = TestThingFactory.create()
        self.admin_user = TestUserFactory(is_staff=True)
        self.token = Token.objects.get_or_create(user=self.admin_user)

        self.client = APIClient()
        self.client.credentials(HTTP_AUTHORIZATION='Token '+self.token[0].key)

        self.response = self.client.get(
            reverse('appname:things-detail', kwargs={'pk': self.thing.pk}),
            )

Stack trace:

Traceback (most recent call last):
  File ".../venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 393, in to_representation
    url = self.get_url(value, self.view_name, request, format)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 331, in get_url
    return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/reverse.py", line 47, in reverse
    url = _reverse(viewname, args, kwargs, request, format, **extra)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/reverse.py", line 60, in _reverse
    url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
  File ".../venv2/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File ".../venv2/lib/python3.8/site-packages/django/urls/resolvers.py", line 685, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'thing-detail' not found. 'thing-detail' is not a valid view function or pattern name.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File ".../myapi/myapp/tests/test_thing.py", line 27, in setUp
    self.response = self.client.get(
  File ".../venv2/lib/python3.8/site-packages/rest_framework/test.py", line 286, in get
    response = super().get(path, data=data, **extra)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/test.py", line 203, in get
    return self.generic('GET', path, **r)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/test.py", line 231, in generic
    return super().generic(
  File ".../venv2/lib/python3.8/site-packages/django/test/client.py", line 470, in generic
    return self.request(**r)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/test.py", line 283, in request
    return super().request(**kwargs)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/test.py", line 235, in request
    request = super().request(**kwargs)
  File ".../venv2/lib/python3.8/site-packages/django/test/client.py", line 709, in request
    self.check_exception(response)
  File ".../venv2/lib/python3.8/site-packages/django/test/client.py", line 571, in check_exception
    raise exc_value
  File ".../venv2/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File ".../venv2/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File ".../venv2/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/viewsets.py", line 114, in view
    return self.dispatch(request, *args, **kwargs)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File ".../venv2/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/mixins.py", line 56, in retrieve
    return Response(serializer.data)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/serializers.py", line 562, in data
    ret = super().data
  File ".../venv2/lib/python3.8/site-packages/rest_framework/serializers.py", line 260, in data
    self._data = self.to_representation(self.instance)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/serializers.py", line 529, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File ".../venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 408, in to_representation
    raise ImproperlyConfigured(msg % self.view_name)
django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "myapp:thing-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.

There are no fields with related objects here. It seems to be behaving as if I'm not supplying the url in the second case, as it's trying to guess what the reverse will be (and it's things, not thing in the url config).

Aucun commentaire:

Enregistrer un commentaire