Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django test RequestFactory does not include request.user

Whenever I use the requestFactory during testing like:

from django.contrib.auth.models import User
from django.test import TestCase
from django.test.client import RequestFactory
from django.test.client import Client
import nose.tools as nt

class TestSomeTestCaseWithUser(TestCase):

    def setUp(self):
        # Every test needs access to the request factory.
        self.factory = RequestFactory()
        self.client = Client()
        self.user_foo = User.objects.create_user('foo', '[email protected]', 'bar')

    def tearDown(self):
        # Delete those objects that are saved in setup
        self.user_foo.delete()

    def test_request_user(self):
        self.client.login( username='foo', password='bar')
        request = self.factory.post('/my/url/', {"somedata": "data"})
        nt.assert_equal(request.user,self.user_foo)

on everything I try with request.user:

AttributeError: 'dict' object has no attribute 'user'

this won't work, so I Added a workaround:

def test_request_user(self):
    # Create an instance of a GET request.
    self.client.login( username='foo', password='bar')
    request = self.factory.post('/my/url/', {"somedata": "data"})
    # a little workaround, because factory does not add the logged in user
    request.user = self.user_foo
    nt.assert_equal(request.user,self.user_foo)

I use request.user a lot in my code... so also in the things I want to (unit)test...

Thanks to this question and answer I found out you need to add the user to the request manually: How to access request.user while testing? and I added this as a workaround.

My questions are:

  • Why is this?
  • It feels like a bug in the request factory, is it? (so is it a workaround, or just an undocumented feature)
  • Or am I doing something else wrong? (combination of test client and factory)
  • Is there a better way to test with logged on users in a request?

I tried this as well: same issue

    response = self.client.post("/my/url/")
    request = response.request

By the way, this answer: Accessing the request.user object when testing Django suggests to use

response.context['user'] 

in stead of

request.user

But in my code this is not the case, and as far as I know request.user is quit normal to use, and to explain my problem, i put the request.user in a test... in my real life, it's not in the tests... it's in the code I want to test.

like image 320
michel.iamit Avatar asked Jun 15 '13 12:06

michel.iamit


1 Answers

sorry... it seems it is a documented feature...

however, it would have been nice to give a better example.

see this.

there it is in the third list item:

It does not support middleware. Session and authentication attributes must be supplied by the test itself if required for the view to function properly.

however... this seem contradictional with the first sentences:

The RequestFactory shares the same API as the test client. However, instead of behaving like a browser, the RequestFactory provides a way to generate a request instance that can be used as the first argument to any view. This means you can test a view function the same way as you would test any other function

especialy the same way

Not sure if I should remove this question.... solving this problem took me a lot of time... than understanding my workaround also...

So I suppose somebody can use this as well..

and I just added a documentation extending request: https://code.djangoproject.com/ticket/20609

like image 125
michel.iamit Avatar answered Nov 06 '22 06:11

michel.iamit