How can i correctly pass arguments to classbasedviews testing Django Rest Framework?

Question:

I want to test some views in DRF project.

The problem comes when I try to check views that have arguments in the urls.

urls.py


    url(r'^(?Pcompany_hash>[dw]+)/(?Ptimestamp>[.d]*)/employees/$',
        EmployeeList.as_view(), name='employeelist'),

[edit: “<” in url has been deleted in purpose, just it isnt considered a tag and thus not shown]

views.py

    class EmployeeList(ListCreateAPIView):
        serializer_class = EmployeeDirectorySerializer

        def inner_company(self):
            company_hash = self.kwargs['company_hash']
            return get_company(company_hash)

        def get_queryset(self):
            return Employee.objects.filter(company=self.inner_company())

test.py


class ApiTests(APITestCase):
    def setUp(self):
        self.factory = APIRequestFactory()
        self.staff = mommy.make('directory.Employee', user__is_staff=True)
        self.employee = mommy.make('directory.Employee')

        self.hash = self.employee.company.company_hash

    def getResponse(self, url, myView, kwargs):
        view = myView.as_view()
        request = self.factory.get(url, kwargs)

        force_authenticate(request, user=user)

        response = view(request)
        return response

    def test_EmployeeList(self):
        kwargs = {'timestamp': 0, 'company_hash': self.hash}
        url = reverse('employeelist', kwargs=kwargs)
        testedView = EmployeeList

        response = self.getResponse(url, testedView,
                kwargs=kwargs)
        self.assertEqual(response.status_code, 200)

I’m getting this error

    company_hash = self.kwargs['company_hash']
KeyError: 'company_hash'

That is the args aren’t been passed to the view.

I’ve tried in so many different ways to pass by the args, can’t find a solution.

Any help is welcomed!

Asked By: monobot

||

Answers:

Check your regex syntax in your URL conf. You aren’t capturing the named group correctly. You have

(?<P 

rather than

(?P<

https://docs.djangoproject.com/en/1.8/topics/http/urls/#named-groups

-James

Answered By: James Schneider

Just found the problem!!

I was using APIRequestFactory()
and should have been using the build in client factory from the APITestCase test class from Django Rest Framework

Answered By: monobot

you just need to specify your kwargs again when calling get() method:

...
...
    def getResponse(self, url, myView, kwargs):
        view = myView.as_view()
        request = self.factory.get(url, kwargs)
        ...
        response = view(request, company_hash=kwargs['company_hash'])
        return response

So your argument will be passed correctly.

NB: i used this solution based on my experience with the mother class of APIRequestfactory, Django RequestFactory.

Answered By: Bachir Mehemmel

You should pass kwargs twice: into reverse(...) and into view(...):

def test_EmployeeList(self):
    # some init here
    auth_user = ...
    hash = ...
    # form kwargs for url /<company_hash>/<timestamp>/employees/
    kwargs = {'company_hash': hash, 'timestamp': 0}
    # form url itself
    url = reverse('employeelist', kwargs=kwargs)
    # then form factory and request
    factory = APIRequestFactory()
    request = factory.get(url)
    force_authenticate(request, user=auth_user)
    # get view
    view = EmployeeList.as_view()
    # run view
    # here you pass kwargs again!
    response = view(request, **kwargs)
    self.assertEqual(response.status_code, 200)

PS. Actually @bachir-mehemmel’s answer lead me to that code but he is wrong telling kwargs should be passed to get (I think he means factory.get). If you open factory.get implementation you’ll see that it is used for payload and not for url.

Answered By: egvo