3

I have a problem with Django Rest Framework's tests. I have a following view:

class AccountDetail(generics.RetrieveUpdateAPIView):
    model = Account
    serializer_class = AccountSerializer
    lookup_field = 'username'
    permission_classes = (permissions.AllowAny,)
    def get_queryset(self):
        return Account.objects.filter(username=self.kwargs.get('username'))

My urls include the following:

account_urls = patterns('',
    url(r'^/(?P<username>[0-9a-zA-Z_-]+)/$', AccountDetail.as_view(), name='account-detail'),
    url(r'^/$', AccountList.as_view(), name='account-list')
)

urlpatterns = patterns('',
    url(r'^api/v1/users', include(account_urls)),
)

When I use the browsable API, everything works alright, but when I write the following test, I get an error:

class TestAccoundDetail(APITestCase):
    def setUp(self):
        factory = APIRequestFactory()
        #set up normal user and token
        self.normal_user = Account.objects.create_user(email="[email protected]", username="useri", password="man")
        request = factory.post('/api/v1/auth/login/', {'email': '[email protected]', 'password': 'man'})
        response = obtain_jwt_token(request)
        self.normal_token = response.data['token']

    def test_details(self):
        factory = APIRequestFactory()
        view = AccountDetail.as_view()

        #unauthenticated
        url = reverse('account-detail', kwargs={'username': 'useri'})
        request = factory.get(url)
        response = view(request)
        self.assertEqual(response.status_code, 200)

AssertionError: Expected view AccountDetail to be called with a URL keyword argument named "username". Fix your URL conf, or set the .lookup_field attribute on the view correctly.

URL seems fine, and the lookup_field is there. What am I missing?

EDIT

I used APIClient instead and it works:

        client = APIClient()

        response = client.get('/api/v1/users/useri/')
        self.assertEqual(response.status_code, 200)

However, I still don't understand why my original test did not work.

2 Answers 2

5

Expanding on @linovias answer, the key is to pass the extra arguments to your view

response = (view, username='useri')

Full test

def test_details(self):
    factory = APIRequestFactory()
    view = AccountDetail.as_view()

    #unauthenticated
    url = reverse('account-detail', kwargs={'username': 'useri'})
    request = factory.get(url)

    response = view(request, username='useri')

    self.assertEqual(response.status_code, 200)
Sign up to request clarification or add additional context in comments.

Comments

5

RequestFactory is to unittest views. It does bypass the middleware and the url layer. Therefore you need to provide the additional arguments by yourself while with the ClientFactory urls.py do it for you.

Edit: In other words,

response = view(request)

should be

response = view(request, "useri")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.