Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert ResourceRelatedField test to pytest styled tests #887

Merged
merged 1 commit into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/settings/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"example",
"debug_toolbar",
"django_filters",
"tests",
]

TEMPLATES = [
Expand Down
113 changes: 0 additions & 113 deletions example/tests/test_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,130 +6,17 @@
from rest_framework.fields import SkipField
from rest_framework.reverse import reverse

from rest_framework_json_api.exceptions import Conflict
from rest_framework_json_api.relations import (
HyperlinkedRelatedField,
ResourceRelatedField,
SerializerMethodHyperlinkedRelatedField,
)
from rest_framework_json_api.utils import format_resource_type

from . import TestBase
from example.models import Author, Blog, Comment, Entry
from example.serializers import CommentSerializer
from example.views import EntryViewSet


class TestResourceRelatedField(TestBase):
def setUp(self):
super(TestResourceRelatedField, 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,
)
for i in range(1, 6):
name = "some_author{}".format(i)
self.entry.authors.add(
Author.objects.create(name=name, email="{}@example.org".format(name))
)

self.comment = Comment.objects.create(
entry=self.entry,
body="testing one two three",
author=Author.objects.first(),
)

def test_data_in_correct_format_when_instantiated_with_blog_object(self):
serializer = BlogFKSerializer(instance={"blog": self.blog})

expected_data = {"type": format_resource_type("Blog"), "id": str(self.blog.id)}

actual_data = serializer.data["blog"]

self.assertEqual(actual_data, expected_data)

def test_data_in_correct_format_when_instantiated_with_entry_object(self):
serializer = EntryFKSerializer(instance={"entry": self.entry})

expected_data = {
"type": format_resource_type("Entry"),
"id": str(self.entry.id),
}

actual_data = serializer.data["entry"]

self.assertEqual(actual_data, expected_data)

def test_deserialize_primitive_data_blog(self):
serializer = BlogFKSerializer(
data={
"blog": {"type": format_resource_type("Blog"), "id": str(self.blog.id)}
}
)

self.assertTrue(serializer.is_valid())
self.assertEqual(serializer.validated_data["blog"], self.blog)

def test_validation_fails_for_wrong_type(self):
with self.assertRaises(Conflict) as cm:
serializer = BlogFKSerializer(
data={"blog": {"type": "Entries", "id": str(self.blog.id)}}
)
serializer.is_valid()
the_exception = cm.exception
self.assertEqual(the_exception.status_code, 409)

def test_serialize_many_to_many_relation(self):
serializer = EntryModelSerializer(instance=self.entry)

type_string = format_resource_type("Author")
author_pks = Author.objects.values_list("pk", flat=True)
expected_data = [{"type": type_string, "id": str(pk)} for pk in author_pks]

self.assertEqual(serializer.data["authors"], expected_data)

def test_deserialize_many_to_many_relation(self):
type_string = format_resource_type("Author")
author_pks = Author.objects.values_list("pk", flat=True)
authors = [{"type": type_string, "id": pk} for pk in author_pks]

serializer = EntryModelSerializer(data={"authors": authors, "comments": []})

self.assertTrue(serializer.is_valid())
self.assertEqual(
len(serializer.validated_data["authors"]), Author.objects.count()
)
for author in serializer.validated_data["authors"]:
self.assertIsInstance(author, Author)

def test_read_only(self):
serializer = EntryModelSerializer(
data={"authors": [], "comments": [{"type": "Comments", "id": 2}]}
)
serializer.is_valid(raise_exception=True)
self.assertNotIn("comments", serializer.validated_data)

def test_invalid_resource_id_object(self):
comment = {
"body": "testing 123",
"entry": {"type": "entry"},
"author": {"id": "5"},
}
serializer = CommentSerializer(data=comment)
assert not serializer.is_valid()
assert serializer.errors == {
"author": ["Invalid resource identifier object: missing 'type' attribute"],
"entry": ["Invalid resource identifier object: missing 'id' attribute"],
}


class TestHyperlinkedFieldBase(TestBase):
def setUp(self):
super(TestHyperlinkedFieldBase, self).setUp()
Expand Down
22 changes: 22 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest

from tests.models import ForeignKeyTarget, ManyToManySource, ManyToManyTarget


@pytest.fixture(autouse=True)
def use_rest_framework_json_api_defaults(settings):
Expand All @@ -19,3 +21,23 @@ def use_rest_framework_json_api_defaults(settings):
settings.JSON_API_FORMAT_FIELD_NAMES = False
settings.JSON_API_FORMAT_TYPES = False
settings.JSON_API_PLURALIZE_TYPES = False


@pytest.fixture
def foreign_key_target(db):
return ForeignKeyTarget.objects.create(name="Target")


@pytest.fixture
def many_to_many_source(db, many_to_many_targets):
source = ManyToManySource.objects.create(name="Source")
source.targets.add(*many_to_many_targets)
return source


@pytest.fixture
def many_to_many_targets(db):
return [
ManyToManyTarget.objects.create(name="Target1"),
ManyToManyTarget.objects.create(name="Target2"),
]
44 changes: 44 additions & 0 deletions tests/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from rest_framework_json_api.relations import ResourceRelatedField
from rest_framework_json_api.serializers import ModelSerializer
from tests.models import (
BasicModel,
ForeignKeySource,
ForeignKeyTarget,
ManyToManySource,
ManyToManyTarget,
)


class BasicModelSerializer(ModelSerializer):
class Meta:
fields = ("text",)
model = BasicModel


class ForeignKeySourceSerializer(ModelSerializer):
target = ResourceRelatedField(queryset=ForeignKeyTarget.objects)

class Meta:
model = ForeignKeySource
fields = ("target",)


class ManyToManySourceSerializer(ModelSerializer):
targets = ResourceRelatedField(many=True, queryset=ManyToManyTarget.objects)

class Meta:
model = ManyToManySource
fields = ("targets",)


class ManyToManyTargetSerializer(ModelSerializer):
class Meta:
model = ManyToManyTarget


class ManyToManySourceReadOnlySerializer(ModelSerializer):
targets = ResourceRelatedField(many=True, read_only=True)

class Meta:
model = ManyToManySource
fields = ("targets",)
162 changes: 160 additions & 2 deletions tests/test_relations.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import pytest
from django.conf.urls import re_path
from rest_framework import status
from rest_framework.routers import SimpleRouter

from rest_framework_json_api.exceptions import Conflict
from rest_framework_json_api.relations import HyperlinkedRelatedField
from rest_framework_json_api.views import ModelViewSet, RelationshipView

from .models import BasicModel
from tests.models import BasicModel
from tests.serializers import (
ForeignKeySourceSerializer,
ManyToManySourceReadOnlySerializer,
ManyToManySourceSerializer,
)


@pytest.mark.urls(__name__)
Expand Down Expand Up @@ -43,6 +49,158 @@ def test_relationship_urls_respect_format_related_links_setting(
assert expected == actual


@pytest.mark.django_db
class TestResourceRelatedField:
@pytest.mark.parametrize(
"format_type,pluralize_type,resource_type",
[
(False, False, "ForeignKeyTarget"),
(False, True, "ForeignKeyTargets"),
("dasherize", False, "foreign-key-target"),
("dasherize", True, "foreign-key-targets"),
],
)
def test_serialize(
self, format_type, pluralize_type, resource_type, foreign_key_target, settings
):
settings.JSON_API_FORMAT_TYPES = format_type
settings.JSON_API_PLURALIZE_TYPES = pluralize_type

serializer = ForeignKeySourceSerializer(instance={"target": foreign_key_target})
expected = {
"type": resource_type,
"id": str(foreign_key_target.pk),
}

assert serializer.data["target"] == expected

@pytest.mark.parametrize(
"format_type,pluralize_type,resource_type",
[
(False, False, "ForeignKeyTarget"),
(False, True, "ForeignKeyTargets"),
("dasherize", False, "foreign-key-target"),
("dasherize", True, "foreign-key-targets"),
],
)
def test_deserialize(
self, format_type, pluralize_type, resource_type, foreign_key_target, settings
):
settings.JSON_API_FORMAT_TYPES = format_type
settings.JSON_API_PLURALIZE_TYPES = pluralize_type

serializer = ForeignKeySourceSerializer(
data={"target": {"type": resource_type, "id": str(foreign_key_target.pk)}}
)

assert serializer.is_valid()
assert serializer.validated_data["target"] == foreign_key_target

@pytest.mark.parametrize(
"format_type,pluralize_type,resource_type",
[
(False, False, "ForeignKeyTargets"),
(False, False, "Invalid"),
(False, False, "foreign-key-target"),
(False, True, "ForeignKeyTarget"),
("dasherize", False, "ForeignKeyTarget"),
("dasherize", True, "ForeignKeyTargets"),
],
)
def test_validation_fails_on_invalid_type(
self, format_type, pluralize_type, resource_type, foreign_key_target, settings
):
settings.JSON_API_FORMAT_TYPES = format_type
settings.JSON_API_PLURALIZE_TYPES = pluralize_type

with pytest.raises(Conflict) as e:
serializer = ForeignKeySourceSerializer(
data={
"target": {"type": resource_type, "id": str(foreign_key_target.pk)}
}
)
serializer.is_valid()
assert e.value.status_code == status.HTTP_409_CONFLICT

@pytest.mark.parametrize(
"format_type,pluralize_type,resource_type",
[
(False, False, "ManyToManyTarget"),
(False, True, "ManyToManyTargets"),
("dasherize", False, "many-to-many-target"),
("dasherize", True, "many-to-many-targets"),
],
)
def test_serialize_many_to_many_relation(
self,
format_type,
pluralize_type,
resource_type,
many_to_many_source,
many_to_many_targets,
settings,
):
settings.JSON_API_FORMAT_TYPES = format_type
settings.JSON_API_PLURALIZE_TYPES = pluralize_type

serializer = ManyToManySourceSerializer(instance=many_to_many_source)
expected = [
{"type": resource_type, "id": str(target.pk)}
for target in many_to_many_targets
]
assert serializer.data["targets"] == expected

@pytest.mark.parametrize(
"format_type,pluralize_type,resource_type",
[
(False, False, "ManyToManyTarget"),
(False, True, "ManyToManyTargets"),
("dasherize", False, "many-to-many-target"),
("dasherize", True, "many-to-many-targets"),
],
)
@pytest.mark.parametrize(
"serializer_class",
[ManyToManySourceSerializer, ManyToManySourceReadOnlySerializer],
)
def test_deserialize_many_to_many_relation(
self,
format_type,
pluralize_type,
resource_type,
serializer_class,
many_to_many_targets,
settings,
):
settings.JSON_API_FORMAT_TYPES = format_type
settings.JSON_API_PLURALIZE_TYPES = pluralize_type

targets = [
{"type": resource_type, "id": target.pk} for target in many_to_many_targets
]
serializer = ManyToManySourceSerializer(data={"targets": targets})
assert serializer.is_valid()
assert serializer.validated_data["targets"] == many_to_many_targets

@pytest.mark.parametrize(
"resource_identifier,error",
[
(
{"type": "ForeignKeyTarget"},
"Invalid resource identifier object: missing 'id' attribute",
),
(
{"id": "1234"},
"Invalid resource identifier object: missing 'type' attribute",
),
],
)
def test_invalid_resource_id_object(self, resource_identifier, error):
serializer = ForeignKeySourceSerializer(data={"target": resource_identifier})
assert not serializer.is_valid()
assert serializer.errors == {"target": [error]}


# Routing setup


Expand Down
Loading