Jim
Jim

Reputation: 14270

How to pass extra keyword arguments when using Django RequestFactory?

I'm trying to write a simple unit test for a view but I'm having trouble passing extra keyword arguments to the view when I'm using RequestFactory to set up the request.

To start, here's the urlpattern:

# app/urls.py
# Example URL: localhost:8000/run/user/1/foo
urlpatterns = [
    url(r'^user/(?P<uid>\d+)/(?P<uname>\w+)/$',
        views.user_kw,
        name='user-kw'),
]

Here's the view I'm testing:

# app/views.py
def user_kw(request, *args, **kwargs):
    uid = kwargs['uid']
    uname = kwargs['uname']
    return render(request, 'run/user.html', context)

Finally, here's the test:

# app/tests.py
def test_user_kw(self):
    factory = RequestFactory()
    # ???
    request = factory.post('user/')
    response = views.user_kw(request)
    self.assertEqual(response.status_code, 200)

As you might expect, when I run the test, I get this error:

======================================================================
ERROR: test_user_kw (run.tests.TestViews)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jones/code/django/testing/run/tests.py", line 53, in test_user_kw
    response = views.user_kw(request, {"uid": 1, "uname": "foobar"})
  File "/Users/jones/code/django/testing/run/views.py", line 28, in user_kw
    uid = kwargs['uid']
KeyError: 'uid'

----------------------------------------------------------------------

The Django documentation on the RequestFactory object doesn't discuss this situation. I looked at the RequestFactory code itself but I couldn't figure out how to set up the object to account for the two keyword arguments contained in the URL. I also couldn't find anything online addressing this situation.

I should add that I did manage to write a test for the case in which I used positional arguments and it works:

def test_user_pos(self):
    factory = RequestFactory()
    request = factory.post('user/')
    response = views.user_pos(request, 1, 'foo')
    self.assertEqual(response.status_code, 200)

I just can't figure out how to rewrite the test for keyword arguments. Perhaps I've been looking at the problem for too long and the answer is staring me in the face, but I just don't see it.

Upvotes: 3

Views: 2224

Answers (1)

Alasdair
Alasdair

Reputation: 308939

You can pass keyword arguments to the user_pos method the normal way:

response = views.user_kw(request, uid=1, uname='foo')

Your error message shows that you tried:

response = views.user_kw(request, {"uid": 1, "uname": "foobar"})

This isn't passing keyword arguments, it's passing a dictionary as a positional argument. Note that you can use ** to unpack the dictionary:

response = views.user_kw(request, **{"uid": 1, "uname": "foobar"})

Upvotes: 7

Related Questions