【问题标题】:django-rest testing views with custom authentication使用自定义身份验证的 django-rest 测试视图
【发布时间】:2017-10-25 23:57:09
【问题描述】:

我尝试测试具有自定义身份验证的视图,主要是因为主身份验证是基于外部登录-注销系统,利用 Redis 作为数据库来存储会话。

Auth 类正在检查请求中的会话 id,是否与 Redis 中的相同 - 如果是,则成功。

我的自定义 authentication.py 看起来像:

from django.utils.six import BytesIO

from rest_framework import authentication
from rest_framework import exceptions

from rest_framework.parsers import JSONParser

import redis


class RedisAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):

    print(request.META)
    token = request.META['HTTP_X_AUTH_TOKEN']
    redis_host = "REDIS_IP_ADRESS"
    redis_db = redis.StrictRedis(host=redis_host)
    user_data = redis_db.get("user_feature:{}".format(token))
    if user_data is None:
        raise exceptions.AuthenticationFailed('No such user or session expired')

    try:
        stream = BytesIO(user_data)  # Decode byte type
        data = JSONParser(stream)  # Parse bytes class and return dict
        current_user_id = data['currentUserId']
        request.session['user_id'] = current_user_id
    except Exception as e:
        print(e)

    return (user_data, None)

我的 views.py 看起来像:

@api_view(['GET', 'POST'])
@authentication_classes((RedisAuthentication, ))
def task_list(request):
    if request.method == 'GET':
        paginator = PageNumberPagination()
        task_list = Task.objects.all()
        result_page = paginator.paginate_queryset(task_list, request)
        serializer = TaskSerializer(result_page, many=True)
        return paginator.get_paginated_response(serializer.data)

    elif request.method == 'POST':
        serializer = PostTaskSerializer(data=request.data)
        if serializer.is_valid():
            user_id = request.session.get('user_id')
            serializer.save(owner_id=user_id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

手动测试通过,但我当前的 pytest 在添加 authentication.py 后失败,并且不知道如何正确修复它 - 尝试强制身份验证,但没有成功。 我认为解决方案之一是使用 fakeredis 来模拟真实的 redis。问题是,这种测试应该是什么样子?

您可以在此处找到测试示例:

@pytest.mark.webtest
class TestListView(TestCase):
    def setUp(self):
        self.client = APIClient()
    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('task_list')
        )
        assert response.status_code == status.HTTP_200_OK

@pytest.mark.webtest
class TestCreateTask(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_user(username='admin', email='xx', password='xx')
    def test_create(self):
        data = {some_data}
        self.client.login(username='xx', password='xx')
        response = self.client.post(
            reverse('task_list'),
            data,
            format='json')
        assert response.status_code == status.HTTP_201_CREATED
        self.client.logout()

提前感谢您的帮助!

【问题讨论】:

  • 您已经找到解决方案了吗?
  • @javidazac 请参阅下面的答案。

标签: django authentication django-rest-framework


【解决方案1】:

我设法使用 mock.patch 装饰器模拟整个 redis 身份验证 - https://docs.python.org/3.5/library/unittest.mock-examples.html#patch-decorators

将import patch放入mock.patch装饰器时,不要插入redis代码存放的绝对模块路径,而是插入redis代码作为模块导入并使用的路径。

我的测试现在看起来像这样:

@mock.patch('api.views.RedisAuthentication.authenticate')
def test_view_url_accessible_by_name(self, mock_redis_auth):

    data = {"foo": 1, "currentUserId": 2, "bar": 3}
    mock_redis_auth.return_value = (data, None)

    response = self.client.get(
        reverse('task_list'),
        HTTP_X_AUTH_TOKEN='foo'
    )
    assert response.status_code == status.HTTP_200_OK

【讨论】:

    猜你喜欢
    • 2017-01-07
    • 2015-12-26
    • 2013-12-29
    • 2015-11-12
    • 2019-11-20
    • 1970-01-01
    • 2015-06-01
    • 2018-07-04
    • 2019-02-02
    相关资源
    最近更新 更多