2

I am learning testing in Django, and have a view which I want to test. This view should only be accessed by staff users. Suppose the view is:

def staff_users(request):
    ....
    # some logic

    return HttpResponseRedirect('/repositories/')

if the request is coming from staff users, it should redirect to repositories otherwise I should get something like permission denied. I am starting with something like in tests.py.

 def test_request_object(self):
        self.user = User.objects.create_user(
        username='abc', email='abc@gmail.com', password='1234')
        request = HttpRequest()
        # User send a request to access repositories
        response = staff_users(request)
        self.assertIsNone(response)

The problem is here I am not associating my request object with any users, and I also got to know about from django.contrib.admin.views.decorators import staff_member_required but not sure how to use them here. Could anyone tell me how should I test my view should only be accessed by staff users?

python
  • 4,403
  • 13
  • 56
  • 103

1 Answers1

4

All you need to do is decorate your view which you want to protect as shown below:

@staff_member_required
def staff_users(request):
    ....
    # some logic

    return HttpResponseRedirect('/repositories/')

If you want a custom logic for testing instead of using django decorator then you can write your own decorator as well.

def staff_users_only(function):
  def wrap(request, *args, **kwargs):

        profile = request.session['user_profile']
        if profile is True: #then its a staff member
             return function(request, *args, **kwargs)
        else:
            return HttpResponseRedirect('/')

  wrap.__doc__=function.__doc__
  wrap.__name__=function.__name__
  return wrap

and use it as:

@staff_users_only
def staff_users(request):
    ....
    # some logic

    return HttpResponseRedirect('/repositories/')

Edit

Association of sessions on request object for testing can be done as:

def test_request_object(self):
    self.user = User.objects.create_user(
    username='abc', email='abc@gmail.com', password='1234')
    request = HttpRequest()
    #create a session which will hold the user profile that will be used in by our custom decorator
    request.session = {} #Session middleware is not available in UnitTest hence create a blank dictionary for testing purpose
    request.session['user_profile'] = self.user.is_staff #assuming its django user.

    # User send a request to access repositories
    response = staff_users(request)

    #Check the response type for appropriate action
    self.assertIsNone(response)

Edit 2

Also it would be a far better idea to use django Client library for testing:

>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'abc', 'password': '1234'})
>>> response.status_code
200
>>> response = c.get('/user/protected-page/')
>>> response.content
b'<!DOCTYPE html...
anand
  • 1,506
  • 14
  • 28
  • Please also show the standard way to do full decoration: `@wraps(function)` in front of `def wrap(request, ...` – Pynchia Nov 08 '15 at 04:00
  • But what about the test cases, how will i associate my request with staff users or normal users? – python Nov 08 '15 at 04:08
  • If you see my `test function`, I am using `request = HttpRequest()` to get a request object. How will I associate my request object with staff or normal users? – python Nov 08 '15 at 04:09
  • @Pynchia kindly explain more, I am not clear on what you meant. – anand Nov 08 '15 at 04:25
  • Anand this makes total sense now :) Wish I can up vote multiple times. Let me test your suggestion, and then will accept. – python Nov 08 '15 at 04:26
  • Hey `request` has no attribute `session` and `user` has not attribute `profile` – python Nov 08 '15 at 04:30
  • @python I have made another edit, I missed that by default `session` is not available in django unit test; you will need to create a blank dictionary to hold session items for testing. – anand Nov 08 '15 at 04:43
  • if your `request session` is an empty dictionary then it does not have any keys like `user_profile`. It is failing here as well – python Nov 08 '15 at 04:46
  • @python yes you need to find out which attribute you want to use as per your user model. I cannot tell you that because you have not shown the `User` model code; If you meant it for django [User](https://docs.djangoproject.com/en/1.8/ref/contrib/auth/#django.contrib.auth.models.User.is_staff) you need check for `user.is_staff`. – anand Nov 08 '15 at 04:47
  • Aren't we creating our `user model` from here `self.user = User.objects.create_user( username='abc', email='abc@gmail.com', password='1234')` – python Nov 08 '15 at 04:49
  • But when you are sending the `request`, how will the `view` know that my `request` is coming from `staff or normal users`. – python Nov 08 '15 at 04:52
  • What [does wraps do](http://stackoverflow.com/questions/308999/what-does-functools-wraps-do) – Pynchia Nov 08 '15 at 04:52
  • Yes `from django.contrib.auth.models import User, AnonymousUser` User model is coming from here. – python Nov 08 '15 at 05:00
  • @python I assume that you are using the django `User` (I cannot be sure, since you need to know from where User is imported) and I making another edit in the answer; kindly put all the information in answer if you are not sure what and where it comes from. – anand Nov 08 '15 at 05:05
  • Thank you Anand for your patience and all the answers :) – python Nov 08 '15 at 05:31