【问题标题】:Adding tests to the Django REST framework tutorial将测试添加到 Django REST 框架教程
【发布时间】:2018-01-25 00:34:03
【问题描述】:

我正在尝试将使用 login_required 装饰器的现有基于函数的视图替换为使用 ModelViewSet 的 Django REST 框架 API。但是,身份验证的工作方式似乎有点不同。

为了尝试使我的单元测试适应 Django REST 框架案例,我克隆了 https://github.com/encode/rest-framework-tutorial 并在顶层目录中添加了 tests.py

import json

from django.contrib.auth.models import User
from django.test import TestCase, Client

from snippets.models import Snippet

class SnippetTestCase(TestCase):
    def setUp(self):
        self.username = 'john_doe'
        self.password = 'foobar'
        self.user = User.objects.create(username=self.username, password=self.password)

        self.client = Client()
        self.snippet = Snippet.objects.create(owner=self.user, code="Foo Bar")

    def test_1(self):
        self.client.login(username=self.username, password=self.password)
        response = self.client.post(
                path='http://localhost:8000/snippets/1/',
                data=json.dumps({'code': 'New code'}),
                content_type="application/json")
        self.assertEqual(response.status_code, 201)

但是,这会返回 403 Forbidden 响应:

Kurts-MacBook-Pro:rest-framework-tutorial kurtpeek$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_1 (tutorial.tests.SnippetTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kurtpeek/Documents/source/rest-framework-tutorial/tutorial/tests.py", line 23, in test_1
    self.assertEqual(response.status_code, 201)
AssertionError: 403 != 201

----------------------------------------------------------------------
Ran 1 test in 0.049s

FAILED (failures=1)
Destroying test database for alias 'default'...

另一方面,使用带有 -a 标志的 HTTPie 可以正常工作:

Kurts-MacBook-Pro:rest-framework-tutorial kurtpeek$ http -a kurtpeek:foobar123 POST http://localhost:8000/snippets/ code="print 123"
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 212
Content-Type: application/json
Date: Thu, 25 Jan 2018 00:11:59 GMT
Location: http://localhost:8000/snippets/2/
Server: WSGIServer/0.2 CPython/3.6.4
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "code": "print 123",
    "highlight": "http://localhost:8000/snippets/2/highlight/",
    "id": 2,
    "language": "python",
    "linenos": false,
    "owner": "kurtpeek",
    "style": "friendly",
    "title": "",
    "url": "http://localhost:8000/snippets/2/"
}

在我看来,这个测试应该满足IsOwnerOrReadonly 权限类的要求:

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.owner == request.user

因为同一个User也是sn-p的owner。任何想法为什么这不起作用,或者我如何构建通过的测试用例?

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    我发现 Django REST 框架有自己的一套测试工具。现在,我从rest_framework.test.APITestCase 继承而不是django.test.TestCase,并在由此创建的self.client 上调用.force_authenticate 方法:

    import json
    
    from django.contrib.auth.models import User
    from django.test import TestCase
    
    from rest_framework.test import APITestCase, force_authenticate
    
    from snippets.models import Snippet
    
    class SnippetTestCase(APITestCase):
        def setUp(self):
            self.username = 'john_doe'
            self.password = 'foobar'
            self.user = User.objects.create(username=self.username, password=self.password)
            self.client.force_authenticate(user=self.user)
    
        def test_1(self):
            response = self.client.post('/snippets/', {'code': 'Foo Bar'}, format='json')
            self.assertEqual(response.status_code, 201)
    

    现在测试通过了。

    【讨论】:

      猜你喜欢
      • 2015-04-19
      • 1970-01-01
      • 2015-08-26
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多