web-dev-qa-db-fra.com

Django Rest Framework - Comment tester ViewSet?

Je ne parviens pas à tester un ViewSet:

class ViewSetTest(TestCase):
    def test_view_set(self):
        factory = APIRequestFactory()
        view = CatViewSet.as_view()
        cat = Cat(name="bob")
        cat.save()

        request = factory.get(reverse('cat-detail', args=(cat.pk,)))
        response = view(request)

J'essaie de reproduire la syntaxe ici:

http://www.Django-rest-framework.org/api-guide/testing#forcing-authentication

Mais je pense que leur vue AccountDetail est différente de mon ViewSet, je reçois donc cette erreur de la dernière ligne:

AttributeError: 'NoneType' object has no attributes 'items'

Y at-il une syntaxe correcte ici ou est-ce que je mélange les concepts? Mes tests APIClient fonctionnent, mais j'utilise l'usine ici parce que j'aimerais éventuellement ajouter "request.user = some_user". Merci d'avance!

Oh, et le test client fonctionne bien:

def test_client_view(self):
    response = APIClient().get(reverse('cat-detail', args=(cat.pk,)))
    self.assertEqual(response.status_code, 200)
22
WBC

Je pense avoir trouvé la syntaxe correcte, mais je ne suis pas sûr que ce soit conventionnel (toujours nouveau pour Django):

def test_view_set(self):
    request = APIRequestFactory().get("")
    cat_detail = CatViewSet.as_view({'get': 'retrieve'})
    cat = Cat.objects.create(name="bob")
    response = cat_detail(request, pk=cat.pk)
    self.assertEqual(response.status_code, 200)

Alors maintenant, cela passe et je peux assigner request.user, ce qui me permet de personnaliser la méthode de récupération sous CatViewSet pour prendre en compte l'utilisateur.

14
WBC

J'ai eu le même problème et j'ai pu trouver une solution.

En regardant le code source, on dirait que la vue s'attend à un argument 'actions' contenant un élément de méthode (donc, un dict).

https://github.com/tomchristie/Django-rest-framework/blob/master/rest_framework/viewsets.py#L69

C'est de là que vient l'erreur que vous obtenez. Vous devrez spécifier les actions d'argument avec un dict contenant les actions autorisées pour cet ensemble de vues, puis vous pourrez le tester correctement.

La cartographie générale va:

{
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
}

http://www.Django-rest-framework.org/tutorial/6-viewsets-and-routers

Dans votre cas, vous voudrez {'get': 'retrieve'} Comme ceci:

class ViewSetTest(TestCase):
    def test_view_set(self):
        factory = APIRequestFactory()
        view = CatViewSet.as_view(actions={'get': 'retrieve'}) # <-- Changed line
        cat = Cat(name="bob")
        cat.save()

        request = factory.get(reverse('cat-detail', args=(cat.pk,)))
        response = view(request)

EDIT: Vous devrez en fait spécifier les actions requises. Code modifié et commentaires pour refléter cela.

9
chrisvans

J'ai trouvé un moyen de le faire sans avoir à créer manuellement le bon jeu de vues et à lui attribuer un mappage d'actions:

from Django.core.urlresolvers import reverse, resolve
...
url = reverse('cat-list')
req = factory.get(url)
view = resolve(url).func
response = view(req)
response.render()
6
Tim Sylvester

Je pense que c'est votre dernière ligne. Vous devez appeler CatViewSet as_view (). J'irais avec:

response = view(request)

étant donné que vous avez déjà défini view = CatViewSet.as_view()

MODIFIER:

Pouvez-vous montrer votre views.py? Plus précisément, quel type de ViewSet avez-vous utilisé? Je suis en train de fouiller dans le code DRF et il semble que vous ne puissiez avoir aucune action associée à votre ViewSet, ce qui déclenche l'erreur.

3
Alex

Je devais travailler avec l'authentification forcée et enfin, voici à quoi ressemble mon scénario:

from Django.test import TestCase
from rest_framework.test import APIRequestFactory
from Django.db.models.query import QuerySet
from rest_framework.test import force_authenticate
from Django.contrib.auth.models import User

from config_app.models import Config
from config_app.apps import ConfigAppConfig
from config_app.views import ConfigViewSet

class ViewsTestCase(TestCase):
    def setUp(self):
        # Create a test instance
        self.config = Config.objects.create(
            ads='{"frequency": 1, "site_id": 1, "network_id": 1}',
            keys={}, methods={}, sections=[], web_app='{"image": 1, "label": 1, "url": 1}',
            subscriptions=[], name='test name', build='test build', version='1.0test', device='desktop',
            platform='Android', client_id=None)

        # Create auth user for views using api request factory
        self.username = 'config_tester'
        self.password = 'goldenstandard'
        self.user = User.objects.create_superuser(self.username, '[email protected]', self.password)

    def tearDown(self):
        pass

    @classmethod
    def setup_class(cls):
        """setup_class() before any methods in this class"""
        pass

    @classmethod
    def teardown_class(cls):
        """teardown_class() after any methods in this class"""
        pass

    def shortDescription(self):
        return None


    def test_view_set1(self):
        """
        No auth example
        """
        api_request = APIRequestFactory().get("")
        detail_view = ConfigViewSet.as_view({'get': 'retrieve'})
        response = detail_view(api_request, pk=self.config.pk)
        self.assertEqual(response.status_code, 401)

    def test_view_set2(self):
        """
        Auth using force_authenticate
        """
        factory = APIRequestFactory()
        user = User.objects.get(username=self.username)
        detail_view = ConfigViewSet.as_view({'get': 'retrieve'})

        # Make an authenticated request to the view...
        api_request = factory.get('')
        force_authenticate(api_request, user=user)
        response = detail_view(api_request, pk=self.config.pk)
        self.assertEqual(response.status_code, 200)

Je l’utilise avec le testeur Django-nose et cela semble bien fonctionner. J'espère que cela aidera ceux qui ont l'authentification activée sur leurs ensembles de vues.

0
radtek