webentwicklung-frage-antwort-db.com.de

So testen Sie einen API-Endpunkt mit Django-rest-framework unter Verwendung von Django-oauth-toolkit zur Authentifizierung

Ich habe ein Django-Rest-Framework Viewset/Router, um einen API-Endpunkt zu definieren. Das Viewset ist wie folgt definiert:

class DocumentViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, TokenHasReadWriteScope]
    model = Document

Und der Router ist definiert als

router = DefaultRouter()
router.register(r'documents', viewsets.DocumentViewSet)

mit URL-Muster url(r'^api/', include(router.urls))

Ich kann diesen Endpunkt im Browser/durch Einrollen erreichen, indem ich das richtige Zugriffstoken erhalte und es für die Autorisierung verwende. Es ist jedoch nicht klar, wie Tests für diesen Endpunkt geschrieben werden sollen.

Folgendes habe ich versucht:

class DocumentAPITests(APITestCase):
    def test_get_all_documents(self):
        user = User.objects.create_user('test', '[email protected]', 'test')
        client = APIClient()
        client.credentials(username="test", password="test")
        response = client.get("/api/documents/")
        self.assertEqual(response.status_code, 200) 

Dies schlägt mit einer HTTP 401-Antwort vom Aufruf client.get() fehl. Wie kann ein API-Endpunkt in DRF mit dem Django-oauth-Toolkit für die oauth2-Authentifizierung richtig getestet werden?

14
Jim

Wenn Sie Tests schreiben, sollten Sie versuchen, alles, was Sie nicht testen, aus dem Test selbst zu extrahieren. Üblicherweise fügen Sie den Setup-Code in die setUp-Methode des Tests ein. Bei API-Tests mit OAuth sind dies normalerweise der Testbenutzer, die OAuth-Anwendung und das aktive Zugriffstoken.

Für Django-oauth-toolkit und andere Django-Anwendungen würde ich immer empfehlen die Tests zu betrachten, um zu sehen, wie sie es tun . Auf diese Weise können Sie unnötige API-Aufrufe, insbesondere für mehrteilige Prozesse wie OAuth, vermeiden und nur die wenigen erforderlichen Modellobjekte erstellen.

def setUp(self):
    self.test_user = UserModel.objects.create_user("test_user", "[email protected]", "123456")

    self.application = Application(
        name="Test Application",
        redirect_uris="http://localhost",
        user=self.test_user,
        client_type=Application.CLIENT_CONFIDENTIAL,
        authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
    )
    self.application.save()

def test_revoke_access_token(self):
    from datetime import datetime
    from Django.utils import timezone

    tok = AccessToken.objects.create(
        user=self.test_user, token='1234567890',
        application=self.application, scope='read write',
        expires=timezone.now() + datetime.timedelta(days=1)
    )

Von dort aus müssen Sie sich nur noch mit dem generierten Token authentifizieren. Sie können dies tun, indem Sie den Header Authorization einfügen oder die Methode force_authenticate verwenden die von Django REST Framework bereitgestellt wird.

25
Kevin Brown

Ich habe die gleiche Bibliothek für OAuth2 verwendet,

Das hat bei mir funktioniert

from oauth2_provider.settings import oauth2_settings
from oauth2_provider.models import get_access_token_model, 
get_application_model
from Django.contrib.auth import get_user_model
from Django.utils import timezone
from rest_framework.test import APITestCase

Application = get_application_model()
AccessToken = get_access_token_model()
UserModel = get_user_model()

class Test_mytest(APITestCase):

    def setUp(self):

        oauth2_settings._SCOPES = ["read", "write", "scope1", "scope2", "resource1"]

        self.test_user = UserModel.objects.create_user("test_user", "[email protected]", "123456")

        self.application = Application.objects.create(
                                                name="Test Application",
                                                redirect_uris="http://localhost http://example.com http://example.org",
                                                user=self.test_user,
                                                client_type=Application.CLIENT_CONFIDENTIAL,
                                                authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
                                            )

        self.access_token = AccessToken.objects.create(
                                                    user=self.test_user,
                                                    scope="read write",
                                                    expires=timezone.now() + timezone.timedelta(seconds=300),
                                                    token="secret-access-token-key",
                                                    application=self.application
                                                )
        # read or write as per your choice
        self.access_token.scope = "read"
        self.access_token.save()

        # correct token and correct scope
        self.auth =  "Bearer {0}".format(self.access_token.token)

    def test_success_response(self):

        url = reverse('my_url',)

        # Obtaining the POST response for the input data
        response = self.client.get(url, HTTP_AUTHORIZATION=self.auth)

        # checking wether the response is success
        self.assertEqual(response.status_code, status.HTTP_200_OK)

Jetzt wird alles wie erwartet funktionieren. Hoffe das hilft. Vielen Dank

0
Shinto Joseph