Skip to content

Commit

Permalink
Convert ResourceRelatedField test to pytest styled tests (#887)
Browse files Browse the repository at this point in the history
  • Loading branch information
sliverc authored Feb 15, 2021
1 parent 5488b18 commit aedc5d9
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 131 deletions.
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

0 comments on commit aedc5d9

Please sign in to comment.