【问题标题】:How can I do the Unit testing of these custom permissions in my Django/Django REST project?如何在我的 Django/Django REST 项目中对这些自定义权限进行单元测试?
【发布时间】:2021-07-30 06:15:58
【问题描述】:

每个人。我希望你一切都好。我是 Django 新手,正在尝试学习 RESTful 开发的基础知识。我只知道 Python,所以这是我目前最适合的。

现在我正在尝试为我的 API 实施单元测试。这是一个在 NBA 球员的姓名和身高上实现 CRUD 的简单模型。在我的模型中,我添加了一个类来描述这些数据并将其转换为带有 ModelViewSets 的视图。我想让这些数据只对特定类型的用户(读写用户)可编辑,只对另一个(只读用户)可读,并且对未经身份验证的用户不可访问。为此,我创建了一个自定义用户模型,并使用自定义权限将其转换为我的视图。现在我想写一些单元测试来检查:

  1. r/w 用户可以创建新播放器
  2. r/w 用户可以获取玩家列表
  3. r/o 用户无法创建新播放器
  4. r/o 用户可以获得玩家列表
  5. 未经身份验证的用户无法创建新播放器
  6. 未经身份验证的用户无法获取玩家列表

这是我的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

还有我的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] 

最后,我的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')),
]

使用AUTH_USER_MODEL = 'api_basic.User' 将自定义用户添加到全局设置所需的所有代码。因此,我已经阅读了文档并观看了一些视频,试图了解如何编写正确的测试,但这些示例与这个问题并没有那么接近。我想请教一些正确方向的指点,以便我可以使用它来构建其余的测试。这是我第一次编写单元测试。

在此先感谢您提供的任何帮助或意见。干杯!

【问题讨论】:

    标签: python django unit-testing django-rest-framework automated-tests


    【解决方案1】:

    这没有什么棘手的。例如,假设我有一项仅对管理员/员工用户可用的服务。这意味着您需要登录并成为管理员。

    在我的测试套件中,我将简单地创建一个 test_permissions 方法,我将在其中执行以下操作:

    • 退出
    • 尝试服务,断言失败
    • 创建普通用户并登录
    • 尝试服务,断言失败
    • 创建管理员用户并登录
    • 试用服务,断言成功

    为了给你一个更具体的例子,这里有一个带有 DRF 的 sn-p 例子。请注意,我正在使用自定义函数和 3rd 方库来做一些事情,但逻辑保持不变:

    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
    

    需要注意的几点:

    • 在这个测试中,我只测试权限。我将使用其他测试来测试字段验证、响应输出/格式等。
    • 如果您发现自己需要特定用户进行多项测试,您可以在 setUp 方法中创建它(在每次测试之前触发)

    因此,如果您想测试特定权限,您只需创建必要的对象/用户并声明您的期望:

    • 拥有此数据的用户应该失败
    • 拥有该数据的用户应该会成功

    【讨论】:

    • 非常感谢。我仍然很难掌握这些概念。我的经验不足终于暴露了。之前我感觉很好,因为我很容易掌握了 Django 和 REST 的所有概念。我以前从未尝试过测试,所以我会继续努力将您的示例转化为我的具体案例。
    猜你喜欢
    • 2016-09-07
    • 1970-01-01
    • 2021-04-25
    • 2020-09-16
    • 2020-10-10
    • 2015-06-01
    • 1970-01-01
    • 2014-12-07
    • 2013-09-29
    相关资源
    最近更新 更多