【问题标题】:Testing Django Rest Framework: how to test hyperlink relations?测试 Django Rest Framework:如何测试超链接关系?
【发布时间】:2020-03-18 17:47:01
【问题描述】:

我正在尝试为自定义的 DjangoRestFramework 超链接相关字段创建真正的单元测试。但我似乎无法绕过这个错误:

django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "relatedtestmodel-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.

这里是单元测试,为了简化示例而进行了精简:

from django.conf.urls import url
from django.test import TestCase, override_settings

from api_tests.models import APITestModel, RelatedTestModel
from api_tests.serializers import APITestModelSerializer


def dummy_view(request, pk):
    pass


urlpatterns = [
    url(r'/path/is/irrelevant/', dummy_view, name='relatedtestmodel-detail')
]


@override_settings(ROOT_URLCONF='tests.test_relations')
class HyperlinkedRelatedFieldTestCase(TestCase):

    def setUp(self):
        self.parent = APITestModel.objects.create()
        self.child = RelatedTestModel.objects.create(parent=self.parent)
        assert self.child.parent.id == self.parent.id

    def test_to_internal_value_correct_error_message(self):
        queryset = APITestModel.objects.all()
        serializer = APITestModelSerializer(queryset, many=True, context={'request': None})
        expected = [{'foo': 'bar'}]
        self.assertEqual(serializer.data, expected)

我或多或少地取消了https://github.com/encode/django-rest-framework/blob/master/tests/test_relations_hyperlink.py 的测试,因为我发现谁比 DRF 的制造商更了解如何对 DRF 进行单元测试?但就目前而言,我的测试拒绝运行。在测试期间,当我尝试访问 serializer.data 以获取断言时,会引发错误。

请特别注意,我使用自定义 urlpatterns 覆盖了设置(这是同一个文件,因此 urlpatterns 在顶部)。所以我不明白为什么 DRF 认为 url 名称不存在 - 我可以清楚地看到我的 url conf 实际上只有那个视图名称!我什至已经编辑了我的实际 URL conf 并将其替换为此处显示的单个命名的虚拟 url 模式,并删除了设置覆盖,只是为了确保不是 override_settings 根本不是工作,但即使那样我也会遇到同样的错误。

在我看来,虚拟 url 模式与 DRF 在他们的测试中所做的完全一样。有人知道发生了什么吗?

更多要求的上下文:

api_tests.models:

from django.db import models

class APITestModel(models.Model):
    pass

class RelatedTestModel(models.Model):
    parent = models.ForeignKey(
        APITestModel,
        related_name='children',
        related_query_name='child'
    )

我目前无法访问回溯,但我可以确认它没有通过我的任何代码 - 它全部与 DjangoRestFramework 代码隔离,基本上完全是关系.py

【问题讨论】:

  • edit您提问并添加APITestModelSerializer的定义。另外,请添加错误的完整回溯。

标签: django unit-testing django-rest-framework


【解决方案1】:

序言

这个问题缺少一些东西

  1. 没有APITestModelSerializer的定义
  2. RelatedTestModel 未在测试中使用,因此与示例无关
  3. 没有错误堆栈跟踪
  4. 断言没有“有用的”预期字典
  5. APITestModel 没有字段,因此无法序列化(您的测试甚至不应该运行)

小事但仍然相关

  1. 您正在 setUp 中创建 APITestModelRelatedTestModel 的特定实例,但在测试中您序列化了 APITestModel 的所有实例
  2. assert self.child.parent.id == self.parent.id 行不应在设置中。它应该在单独的测试中

我的改变

  1. 我删除了与上述问题无关的所有信息
  2. 我在APITestModel 中添加了一个整数字段
  3. 我将 urlpatterns 元素从 url(...) 更改为 path(...)
  4. 我在相对路径中添加了一个正则表达式
  5. 序列化程序是HyperlinkedModelSerializer 的子类,包括字段“url”和“year”
  6. 我的项目和应用程序 urls.py 文件是“库存”文件(此处未显示),以强调此测试可单独解析路径。
  7. @override_settings(ROOT_URLCONF='tests.test_relations') 更改为@override_settings(ROOT_URLCONF=__name__)

代码

models.py

​​>
from django.db import models


class APITestModel(models.Model):
    year = models.IntegerField(null=False)

serializers.py

​​>
from rest_framework import serializers

from api.models import APITestModel


class APITestModelSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = APITestModel
        fields = ["url", "year"]

test_serializers.py

​​>
from django.test import TestCase, override_settings
from django.urls import path

from api.models import APITestModel
from api.serializers import APITestModelSerializer

urlpatterns = [
    path('whateveryouwant/<int:pk>/', lambda request: None, name='apitestmodel-detail'),
]


@override_settings(ROOT_URLCONF=__name__)
class HyperlinkedRelatedFieldTestCase(TestCase):

    def setUp(self):
        # Populate db with APITestModel instances
        _ = APITestModel.objects.create(year=1960)
        _ = APITestModel.objects.create(year=1961)
        _ = APITestModel.objects.create(year=1962)

    def test_to_internal_value_correct_error_message(self):
        queryset = APITestModel.objects.all()
        serializer = APITestModelSerializer(queryset, many=True, context={'request': None})
        expected = [
            {'url': '/whateveryouwant/1/', 'year': 1960},
            {'url': '/whateveryouwant/2/', 'year': 1961},
            {'url': '/whateveryouwant/3/', 'year': 1962},
        ]
        self.assertEqual(serializer.data, expected)

项目中的其他文件是django + djangorestframework自动创建的默认文件。

对于未来的读者,我用这个工作代码创建了一个 github 项目,可以在这里找到:https://github.com/Alechan/drf_test_hyperlink_relations

【讨论】:

    猜你喜欢
    • 2016-12-28
    • 2014-05-29
    • 1970-01-01
    • 2016-06-25
    • 2015-02-06
    • 2018-05-14
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多