Django Rest Framework - How to test ViewSet?

前端 未结 5 1718
萌比男神i
萌比男神i 2021-01-31 09:24

I\'m having trouble testing a ViewSet:

class ViewSetTest(TestCase):
    def test_view_set(self):
        factory = APIRequestFactory()
        view = CatViewSet.         


        
相关标签:
5条回答
  • 2021-01-31 09:44

    I think I found the correct syntax, but not sure if it is conventional (still new to 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)
    

    So now this passes and I can assign request.user, which allows me to customize the retrieve method under CatViewSet to consider the user.

    0 讨论(0)
  • 2021-01-31 09:51

    I had the same issue, and was able to find a solution.

    Looking at the source code, it looks like the view expects there to be an argument 'actions' that has a method items ( so, a dict ).

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

    This is where the error you're getting is coming from. You'll have to specify the argument actions with a dict containing the allowed actions for that viewset, and then you'll be able to test the viewset properly.

    The general mapping goes:

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

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

    In your case you'll want {'get': 'retrieve'} Like so:

    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: You'll actually need to specify the required actions. Changed code and comments to reflect this.

    0 讨论(0)
  • 2021-01-31 09:55

    I found a way to do this without needing to manually create the right viewset and give it an action mapping:

    from django.core.urlresolvers import reverse, resolve
    ...
    url = reverse('cat-list')
    req = factory.get(url)
    view = resolve(url).func
    response = view(req)
    response.render()
    
    0 讨论(0)
  • 2021-01-31 09:57

    I think it's your last line. You need to call the CatViewSet as_view(). I would go with:

    response = view(request)
    

    given that you already defined view = CatViewSet.as_view()

    EDIT:

    Can you show your views.py? Specifically, what kind of ViewSet did you use? I'm digging through the DRF code and it looks like you may not have any actions mapped to your ViewSet, which is triggering the error.

    0 讨论(0)
  • 2021-01-31 10:07

    I needed to get this working with force authentication, and finally got it, here is what my test case looks like:

    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, 'test@example.com', 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)
    

    I'm using this with the django-nose test runner and it seems to be working well. Hope it helps those that have auth enabled on their viewsets.

    0 讨论(0)
提交回复
热议问题