她是我想要进行单元测试的示例权限。
# permissions.py
from myapp.models import Membership
class IsOrganizationOwner(permissions.BasePermission):
"""
Custom permission to allow only owner of the organization to do a certian task.
"""
def has_object_permission(self, request, view, obj):
try:
membership = Membership.objects.get(user = request.user, organization = obj)
except Membership.DoesNotExist:
return False
return membership.is_admin
以及它的应用方式
# viewsets.py
class OrganizationViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Organizations to be viewed or edited.
"""
permission_classes = (permissions.IsAuthenticated, IsOrganizationOwner,)
queryset = Organization.objects.all().order_by('name')
serializer_class = OrganizationSerializer
现在我对django测试非常新,我不知道如何测试这个权限。任何帮助将不胜感激。
答案 0 :(得分:10)
这是一种方法:
InputStream is = YourTestClassName.class.getClassLoader().getResourceAsStream("your/package/name/testFiles/config.properties")
我使用了library我写的模拟django queryset函数来使测试更小,更易读。但如果您愿意,可以使用from django_mock_queries.query import MockSet
from mock import patch, MagicMock
from unittest import TestCase
class TestPermissions(TestCase):
memberships = MockSet()
patch_memberships = patch('myapp.models.Membership.objects', memberships)
def setUp(self):
self.permission = IsOrganizationOwner()
self.memberships.clear()
self.request = MagicMock(user=MagicMock())
self.view = MagicMock()
def create_membership(self, organization, is_admin):
self.request.user.is_admin = is_admin
self.memberships.add(
MagicMock(user=self.request.user, organization=organization)
)
@patch_memberships
def test_permissions_is_organization_owner_returns_false_when_membership_does_not_exist(self):
org = MagicMock()
self.assertFalse(self.permission.has_object_permission(self.request, self.view, org))
@patch_memberships
def test_permissions_is_organization_owner_returns_false_when_membership_is_not_admin(self):
org = MagicMock()
self.create_membership(org, False)
self.assertFalse(self.permission.has_object_permission(self.request, self.view, org))
@patch_memberships
def test_permissions_is_organization_owner_returns_true_when_membership_is_admin(self):
org = MagicMock()
self.create_membership(org, True)
self.assertTrue(self.permission.has_object_permission(self.request, self.view, org))
或Mock
仅修补您需要的内容。
编辑:为了完整起见,我们假设您还想进行集成测试MagicMock
,这里有一些测试:
OrganizationViewSet
正如其他人所指出的那样,您也需要这些测试,而不是每个可能的测试用例。单元测试最适合这种情况,因为集成测试会写入数据库等,并且会使CI过程变慢 - 以防这类事情与您相关。
答案 1 :(得分:1)
我本人正在为此作斗争,我想我找到了一个简单的解决方案,可以单独测试权限检查的行为,而不必模拟所有内容。由于此答复是在原始答案后的四年后提出的,因此从那时起Django可能已经有了很大的发展。
测试权限似乎就像实例化权限并使用人为对象测试其has_permission
方法一样容易。例如,我使用IsAdminUser
权限对此进行了测试,然后测试通过了:
from django.contrib.auth.models import User
from django.test import RequestFactory, TestCase
from rest_framework.permissions import IsAdminUser
class IsAdminUserTest(TestCase):
def test_admin_user_returns_true(self):
admin_user = User.objects.create(username='foo', is_staff=True)
factory = RequestFactory()
request = factory.delete('/')
request.user = admin_user
permission_check = IsAdminUser()
permission = permission_check.has_permission(request, None)
self.assertTrue(permission)
在用户实例中将is_staff
更改为False
会导致测试失败,就像我期望的那样。
使用实际示例进行更新
我写了我自己的自定义权限,以检查用户是否是管理员(工作人员用户),否则只允许只读操作。注意,由于这是一个单元测试,因此它不与任何端点交互,甚至不试图模拟它们。它只是测试权限检查的预期行为。
这是许可:
from rest_framework import permissions
class IsAdminUserOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
return request.user.is_staff
这是完整的单元测试套件:
from django.contrib.auth.models import User
from django.test import RequestFactory, TestCase
from community.permissions import IsAdminUserOrReadOnly
class IsAdminOrReadOnlyTest(TestCase):
def setUp(self):
self.admin_user = User.objects.create(username='foo', is_staff=True)
self.non_admin_user = User.objects.create(username='bar')
self.factory = RequestFactory()
def test_admin_user_returns_true(self):
request = self.factory.delete('/')
request.user = self.admin_user
permission_check = IsAdminUserOrReadOnly()
permission = permission_check.has_permission(request, None)
self.assertTrue(permission)
def test_admin_user_returns_true_on_safe_method(self):
request = self.factory.get('/')
request.user = self.admin_user
permission_check = IsAdminUserOrReadOnly()
permission = permission_check.has_permission(request, None)
self.assertTrue(permission)
def test_non_admin_user_returns_false(self):
request = self.factory.delete('/')
request.user = self.non_admin_user
permission_check = IsAdminUserOrReadOnly()
permission = permission_check.has_permission(request, None)
self.assertFalse(permission)
def test_non_admin_user_returns_true_on_safe_method(self):
request = self.factory.get('/')
request.user = self.non_admin_user
permission_check = IsAdminUserOrReadOnly()
permission = permission_check.has_permission(request, None)
self.assertTrue(permission)
我假设您可以对要为其写入权限的任何用户属性使用类似的模式。
在进行集成/功能测试时,只有这样,我才会担心此权限如何影响API的接口。
答案 2 :(得分:0)
作为上述方法的一个小增强/替代,我将使用pytest的admin_user
夹具来提供django支持:
https://pytest-django.readthedocs.io/en/latest/helpers.html#admin-user-an-admin-user-superuser
一个快乐的路径测试可能看起来像这样:
def test_returns_200_when_user_is_authenticated(self,
client, admin_user):
client.force_login(admin_user)
response = client.put('/my_url/pk/', data={'some data'},
content_type='application/json'))
assert response.status_code == 200
您还可以测试用户未登录的相反情况:
def test_returns_403_when_user_is_not_authenticated(
self, client):
response = client.put('/my_url/pk/', data={'some data'},
content_type='application/json'))
assert response.status_code == 403