简体   繁体   中英

How can I do the Unit testing of these custom permissions in my Django/Django REST project?

everyone. I hope you're doing well. I'm a Django newbie, trying to learn the basics of RESTful development. I only know Python, so this is my best fit for the moment.

Right now I'm trying to implement Unit tests for my API. It's a simple model to implement CRUD on the names and heights of NBA players. In my models I added a class to describe this data and translated it to a view with ModelViewSets. I wanted to make this data editable only for a specific type of user (a read-write user), only readable for another (read-only user) as well as unaccesible to non-authenticated users. To do so, I created a custom User Model and translated it to my views with a custom permission. Now I want to write a few Unit tests to check that:

  1. r/w user can create a new player
  2. r/w user can get a list of players
  3. r/o user cannot create a new player
  4. r/o user can get a list of players
  5. unauthenticated user cannot create a new player
  6. unauthenticated user cannot get a list of players

Here is my models.py :

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    ROLES = [('read-only', 'read-only'), ('read-write', 'read-write'),]
    role = models.CharField(max_length=32, choices=ROLES, default='read-only')
# Create your models here.
class NBAplayers(models.Model):
    first_name = models.CharField(max_length=100)
    h_in = models.DecimalField(max_digits=5, decimal_places=2)
    h_meters = models.DecimalField(max_digits=5, decimal_places=2)
    last_name = models.CharField(max_length=120)

    def __str__(self):
        return self.first_name

And my views.py :

from .models import NBAplayers, User
from .serializers import NBAplayersSerializer
from rest_framework.response import Response
from rest_framework import status, viewsets, permissions

class ReadOnlyPermission(permissions.BasePermission):

    def has_permission(self, request, view):
        requests = ('POST', 'PUT', 'DELETE', 'PATCH')
        user = request.user
        role = User.role
        if user.is_anonymous:  # Not Authenticated
            return request.method == 'GET'            
        else:    
            if role == 'read-write':
                return request.method in requests + ('GET',)
            else:  # Read Only User
                return request.method == 'GET'

class NBAPlayersViewSet(viewsets.ModelViewSet):
    serializer_class = NBAplayersSerializer
    queryset = NBAplayers.objects.all()
    permission_classes = [ReadOnlyPermission] 

And Finally, my urls.py :

from django.contrib import admin
from django.urls import path, include
from .views import  NBAPlayersViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('players', NBAPlayersViewSet, basename = 'Players list')


urlpatterns = [
    #djoser basic authentication
    #Routers URLs
    path('', include(router.urls)),
    path('players/<int:pk>/', include(router.urls)),
    path('', include('djoser.urls')),
    path('', include('djoser.urls.authtoken')),
]

All the code above required to add the custom user to the global settings with AUTH_USER_MODEL = 'api_basic.User' . So, I've read the documentation and watched a few videos trying to understand how to write the proper tests, but the examples are not that close to this problem. I wanted to ask for a few pointers in the right direction, so that I can use it to build the rest of the tests. This is my first time writing unit tests.

Thank you beforehand for any help or input you can give. Cheers!

There's nothing tricky about this. For example, let's say I have a service that is only available to Admin/Staff users. It means you need to be both logged in and be an Admin.

In my test suite, I'll simply create a test_permissions method where I'll do something like:

  • Be logged out
  • Try the service, assert failure
  • Create normal user and log him in
  • Try the service, assert failure
  • Create admin user and log him in
  • Try the service, assert success

To give you a more concrete example, here's a snippet example with DRF. Do note that I'm using custom functions and 3rd party libraries to do some stuff, but the logic remains the same:

class TestCaseSuite(Base):

    def test_permissions(self):
        user = UserFactory()
        admin = AdminFactory()
        # 401 Not authenticated
        self.api_client.logout()
        response = self.api_client.post(url, data=data)
        assert response.status_code == 401
        # 403 Not admin
        self.api_client.force_authenticate(user)
        response = self.api_client.post(url, data=data)
        assert response.status_code == 403
        # 201 Admin
        self.api_client.logout()
        self.api_client.force_authenticate(admin)
        response = self.api_client.post(url, data=data)
        assert response.status_code == self.success_code
    
    # ...
    # other tests for that service like: 
    #    testing custom fields
    #    testing a successful call and the response output
    #    testing side-effects, like when sending an email or whatnot
    #    etc

A few things to note:

  • In THIS test, I'm ONLY testing permissions. I'll use other tests for testing field validation, response output/format, etc.
  • If you find yourself needing a specific user for several tests, you could create it in the setUp method (which is triggered before EVERY test)

So, if you want to test specific permissions, you simply have to create the necessary objects/users and assert your expectations:

  • user with THIS data should fail
  • user with THAT data should succeed
  • etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM