From 45cd622ff51bcbeebb959777a37c84fd7f476225 Mon Sep 17 00:00:00 2001 From: Oliver Sauder Date: Wed, 17 Feb 2021 17:27:21 +0400 Subject: [PATCH] Convert HyperlinkedRelatedField tests to pytest style --- example/tests/test_relations.py | 195 -------------------------------- tests/conftest.py | 12 +- tests/test_relations.py | 134 ++++++++++++++++------ 3 files changed, 109 insertions(+), 232 deletions(-) delete mode 100644 example/tests/test_relations.py diff --git a/example/tests/test_relations.py b/example/tests/test_relations.py deleted file mode 100644 index 6d1cf83b..00000000 --- a/example/tests/test_relations.py +++ /dev/null @@ -1,195 +0,0 @@ -from __future__ import absolute_import - -from django.test.client import RequestFactory -from django.utils import timezone -from rest_framework import serializers -from rest_framework.fields import SkipField -from rest_framework.reverse import reverse - -from rest_framework_json_api.relations import ( - HyperlinkedRelatedField, - ResourceRelatedField, - SerializerMethodHyperlinkedRelatedField, -) - -from . import TestBase -from example.models import Author, Blog, Comment, Entry -from example.views import EntryViewSet - - -class TestHyperlinkedFieldBase(TestBase): - def setUp(self): - super(TestHyperlinkedFieldBase, self).setUp() - self.blog = Blog.objects.create(name="Some Blog", tagline="It's a blog") - self.entry = Entry.objects.create( - blog=self.blog, - headline="headline", - body_text="body_text", - pub_date=timezone.now(), - mod_date=timezone.now(), - n_comments=0, - n_pingbacks=0, - rating=3, - ) - self.comment = Comment.objects.create( - entry=self.entry, - body="testing one two three", - ) - - self.request = RequestFactory().get( - reverse("entry-detail", kwargs={"pk": self.entry.pk}) - ) - self.view = EntryViewSet( - request=self.request, kwargs={"entry_pk": self.entry.id} - ) - - -class TestHyperlinkedRelatedField(TestHyperlinkedFieldBase): - def test_single_hyperlinked_related_field(self): - field = HyperlinkedRelatedField( - related_link_view_name="entry-blog", - related_link_url_kwarg="entry_pk", - self_link_view_name="entry-relationships", - read_only=True, - ) - field._context = {"request": self.request, "view": self.view} - field.field_name = "blog" - - self.assertRaises(NotImplementedError, field.to_representation, self.entry) - self.assertRaises(SkipField, field.get_attribute, self.entry) - - links_expected = { - "self": "http://testserver/entries/{}/relationships/blog".format( - self.entry.pk - ), - "related": "http://testserver/entries/{}/blog".format(self.entry.pk), - } - got = field.get_links(self.entry) - self.assertEqual(got, links_expected) - - def test_many_hyperlinked_related_field(self): - field = HyperlinkedRelatedField( - related_link_view_name="entry-comments", - related_link_url_kwarg="entry_pk", - self_link_view_name="entry-relationships", - read_only=True, - many=True, - ) - field._context = {"request": self.request, "view": self.view} - field.field_name = "comments" - - self.assertRaises( - NotImplementedError, field.to_representation, self.entry.comments.all() - ) - self.assertRaises(SkipField, field.get_attribute, self.entry) - - links_expected = { - "self": "http://testserver/entries/{}/relationships/comments".format( - self.entry.pk - ), - "related": "http://testserver/entries/{}/comments".format(self.entry.pk), - } - got = field.child_relation.get_links(self.entry) - self.assertEqual(got, links_expected) - - -class TestSerializerMethodHyperlinkedRelatedField(TestHyperlinkedFieldBase): - def test_single_serializer_method_hyperlinked_related_field(self): - serializer = EntryModelSerializerWithHyperLinks( - instance=self.entry, context={"request": self.request, "view": self.view} - ) - field = serializer.fields["blog"] - - self.assertRaises(NotImplementedError, field.to_representation, self.entry) - self.assertRaises(SkipField, field.get_attribute, self.entry) - - expected = { - "self": "http://testserver/entries/{}/relationships/blog".format( - self.entry.pk - ), - "related": "http://testserver/entries/{}/blog".format(self.entry.pk), - } - got = field.get_links(self.entry) - self.assertEqual(got, expected) - - def test_many_serializer_method_hyperlinked_related_field(self): - serializer = EntryModelSerializerWithHyperLinks( - instance=self.entry, context={"request": self.request, "view": self.view} - ) - field = serializer.fields["comments"] - - self.assertRaises(NotImplementedError, field.to_representation, self.entry) - self.assertRaises(SkipField, field.get_attribute, self.entry) - - expected = { - "self": "http://testserver/entries/{}/relationships/comments".format( - self.entry.pk - ), - "related": "http://testserver/entries/{}/comments".format(self.entry.pk), - } - got = field.get_links(self.entry) - self.assertEqual(got, expected) - - def test_get_blog(self): - serializer = EntryModelSerializerWithHyperLinks(instance=self.entry) - got = serializer.get_blog(self.entry) - expected = self.entry.blog - - self.assertEqual(got, expected) - - def test_get_comments(self): - serializer = EntryModelSerializerWithHyperLinks(instance=self.entry) - got = serializer.get_comments(self.entry) - expected = self.entry.comments.all() - - self.assertListEqual(list(got), list(expected)) - - -class BlogResourceRelatedField(ResourceRelatedField): - def get_queryset(self): - return Blog.objects - - -class BlogFKSerializer(serializers.Serializer): - blog = BlogResourceRelatedField() - - -class EntryFKSerializer(serializers.Serializer): - entry = ResourceRelatedField(queryset=Entry.objects) - - -class EntryModelSerializer(serializers.ModelSerializer): - authors = ResourceRelatedField(many=True, queryset=Author.objects) - comments = ResourceRelatedField(many=True, read_only=True) - - class Meta: - model = Entry - fields = ("authors", "comments") - - -class EntryModelSerializerWithHyperLinks(serializers.ModelSerializer): - blog = SerializerMethodHyperlinkedRelatedField( - related_link_view_name="entry-blog", - related_link_url_kwarg="entry_pk", - self_link_view_name="entry-relationships", - many=True, - ) - comments = SerializerMethodHyperlinkedRelatedField( - related_link_view_name="entry-comments", - related_link_url_kwarg="entry_pk", - self_link_view_name="entry-relationships", - many=True, - ) - - class Meta: - model = Entry - fields = ( - "blog", - "comments", - ) - - def get_blog(self, obj): - return obj.blog - - def get_comments(self, obj): - return obj.comments.all() diff --git a/tests/conftest.py b/tests/conftest.py index fbd3f453..22be93a1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,11 @@ import pytest -from tests.models import ForeignKeyTarget, ManyToManySource, ManyToManyTarget +from tests.models import ( + BasicModel, + ForeignKeyTarget, + ManyToManySource, + ManyToManyTarget, +) @pytest.fixture(autouse=True) @@ -23,6 +28,11 @@ def use_rest_framework_json_api_defaults(settings): settings.JSON_API_PLURALIZE_TYPES = False +@pytest.fixture +def model(db): + return BasicModel.objects.create(text="Model") + + @pytest.fixture def foreign_key_target(db): return ForeignKeyTarget.objects.create(name="Target") diff --git a/tests/test_relations.py b/tests/test_relations.py index 4cc9833d..d66c602f 100644 --- a/tests/test_relations.py +++ b/tests/test_relations.py @@ -1,10 +1,16 @@ import pytest from django.conf.urls import re_path from rest_framework import status +from rest_framework.fields import SkipField from rest_framework.routers import SimpleRouter +from rest_framework.serializers import Serializer from rest_framework_json_api.exceptions import Conflict -from rest_framework_json_api.relations import HyperlinkedRelatedField +from rest_framework_json_api.relations import ( + HyperlinkedRelatedField, + SerializerMethodHyperlinkedRelatedField, +) +from rest_framework_json_api.utils import format_link_segment from rest_framework_json_api.views import ModelViewSet, RelationshipView from tests.models import BasicModel from tests.serializers import ( @@ -14,41 +20,6 @@ ) -@pytest.mark.urls(__name__) -@pytest.mark.parametrize( - "format_related_links,expected_url_segment", - [ - (None, "relatedField_name"), - ("dasherize", "related-field-name"), - ("camelize", "relatedFieldName"), - ("capitalize", "RelatedFieldName"), - ("underscore", "related_field_name"), - ], -) -def test_relationship_urls_respect_format_related_links_setting( - settings, format_related_links, expected_url_segment -): - settings.JSON_API_FORMAT_RELATED_LINKS = format_related_links - - model = BasicModel(text="Some text") - - field = HyperlinkedRelatedField( - self_link_view_name="basic-model-relationships", - related_link_view_name="basic-model-related", - read_only=True, - ) - field.field_name = "relatedField_name" - - expected = { - "self": f"/basic_models/{model.pk}/relationships/{expected_url_segment}/", - "related": f"/basic_models/{model.pk}/{expected_url_segment}/", - } - - actual = field.get_links(model) - - assert expected == actual - - @pytest.mark.django_db class TestResourceRelatedField: @pytest.mark.parametrize( @@ -201,6 +172,97 @@ def test_invalid_resource_id_object(self, resource_identifier, error): assert serializer.errors == {"target": [error]} +class TestHyperlinkedRelatedField: + @pytest.fixture + def instance(self): + # dummy instance + return object() + + @pytest.fixture + def serializer(self): + class HyperlinkedRelatedFieldSerializer(Serializer): + single = HyperlinkedRelatedField( + self_link_view_name="basic-model-relationships", + related_link_view_name="basic-model-related", + read_only=True, + ) + many = HyperlinkedRelatedField( + self_link_view_name="basic-model-relationships", + related_link_view_name="basic-model-related", + read_only=True, + many=True, + ) + single_serializer_method = SerializerMethodHyperlinkedRelatedField( + self_link_view_name="basic-model-relationships", + related_link_view_name="basic-model-related", + read_only=True, + ) + many_serializer_method = SerializerMethodHyperlinkedRelatedField( + self_link_view_name="basic-model-relationships", + related_link_view_name="basic-model-related", + read_only=True, + many=True, + ) + + def get_single_serializer_method(self, obj): # pragma: no cover + raise NotImplementedError + + def get_many_serializer_method(self, obj): # pragma: no cover + raise NotImplementedError + + return HyperlinkedRelatedFieldSerializer() + + @pytest.fixture( + params=["single", "many", "single_serializer_method", "many_serializer_method"] + ) + def field(self, serializer, request): + field = serializer.fields[request.param] + field.field_name = request.param + return field + + def test_get_attribute(self, model, field): + with pytest.raises(SkipField): + field.get_attribute(model) + + def test_to_representation(self, model, field): + with pytest.raises(NotImplementedError): + field.to_representation(model) + + @pytest.mark.urls(__name__) + @pytest.mark.parametrize( + "format_related_links", + [ + None, + "dasherize", + "camelize", + "capitalize", + "underscore", + ], + ) + def test_get_links( + self, + format_related_links, + field, + settings, + model, + ): + settings.JSON_API_FORMAT_RELATED_LINKS = format_related_links + + link_segment = format_link_segment(field.field_name) + + expected = { + "self": f"/basic_models/{model.pk}/relationships/{link_segment}/", + "related": f"/basic_models/{model.pk}/{link_segment}/", + } + + if hasattr(field, "child_relation"): + # many case + field = field.child_relation + + actual = field.get_links(model) + assert expected == actual + + # Routing setup