From d59d3caf3213686e9c762430a3ab21e28b6e367b Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Sat, 26 Sep 2015 11:53:20 +0200 Subject: [PATCH] Separated natural key serialization tests --- tests/serializers/models.py | 21 +++++++++ tests/serializers/test_natural.py | 70 ++++++++++++++++++++++++++++ tests/serializers/tests.py | 16 +++++++ tests/serializers_regress/models.py | 19 -------- tests/serializers_regress/tests.py | 72 +---------------------------- 5 files changed, 109 insertions(+), 89 deletions(-) create mode 100644 tests/serializers/test_natural.py diff --git a/tests/serializers/models.py b/tests/serializers/models.py index 6532ea953e..c3663b5339 100644 --- a/tests/serializers/models.py +++ b/tests/serializers/models.py @@ -157,3 +157,24 @@ class Player(models.Model): def __str__(self): return '%s (%d) playing for %s' % (self.name, self.rank, self.team.to_string()) + + +# ******** Models for test_natural.py *********** + +class NaturalKeyAnchorManager(models.Manager): + def get_by_natural_key(self, data): + return self.get(data=data) + + +class NaturalKeyAnchor(models.Model): + objects = NaturalKeyAnchorManager() + + data = models.CharField(max_length=100, unique=True) + title = models.CharField(max_length=100, null=True) + + def natural_key(self): + return (self.data,) + + +class FKDataNaturalKey(models.Model): + data = models.ForeignKey(NaturalKeyAnchor, models.SET_NULL, null=True) diff --git a/tests/serializers/test_natural.py b/tests/serializers/test_natural.py new file mode 100644 index 0000000000..6682e5cdd8 --- /dev/null +++ b/tests/serializers/test_natural.py @@ -0,0 +1,70 @@ +from __future__ import unicode_literals + +from django.core import serializers +from django.db import connection +from django.test import TestCase + +from .models import FKDataNaturalKey, NaturalKeyAnchor +from .tests import register_tests + + +class NaturalKeySerializerTests(TestCase): + pass + + +def natural_key_serializer_test(format, self): + # Create all the objects defined in the test data + with connection.constraint_checks_disabled(): + objects = [ + NaturalKeyAnchor.objects.create(id=1100, data="Natural Key Anghor"), + FKDataNaturalKey.objects.create(id=1101, data_id=1100), + FKDataNaturalKey.objects.create(id=1102, data_id=None), + ] + # Serialize the test database + serialized_data = serializers.serialize(format, objects, indent=2, + use_natural_foreign_keys=True) + + for obj in serializers.deserialize(format, serialized_data): + obj.save() + + # Assert that the deserialized data is the same + # as the original source + for obj in objects: + instance = obj.__class__.objects.get(id=obj.pk) + self.assertEqual(obj.data, instance.data, + "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % ( + obj.pk, obj.data, type(obj.data), instance, type(instance.data)) + ) + + +def natural_key_test(format, self): + book1 = {'data': '978-1590597255', 'title': 'The Definitive Guide to ' + 'Django: Web Development Done Right'} + book2 = {'data': '978-1590599969', 'title': 'Practical Django Projects'} + + # Create the books. + adrian = NaturalKeyAnchor.objects.create(**book1) + james = NaturalKeyAnchor.objects.create(**book2) + + # Serialize the books. + string_data = serializers.serialize(format, NaturalKeyAnchor.objects.all(), + indent=2, use_natural_foreign_keys=True, + use_natural_primary_keys=True) + + # Delete one book (to prove that the natural key generation will only + # restore the primary keys of books found in the database via the + # get_natural_key manager method). + james.delete() + + # Deserialize and test. + books = list(serializers.deserialize(format, string_data)) + self.assertEqual(len(books), 2) + self.assertEqual(books[0].object.title, book1['title']) + self.assertEqual(books[0].object.pk, adrian.pk) + self.assertEqual(books[1].object.title, book2['title']) + self.assertEqual(books[1].object.pk, None) + + +# Dynamically register tests for each serializer +register_tests(NaturalKeySerializerTests, 'test_%s_natural_key_serializer', natural_key_serializer_test) +register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_keys', natural_key_test) diff --git a/tests/serializers/tests.py b/tests/serializers/tests.py index ffd573c0cc..2de9ce8796 100644 --- a/tests/serializers/tests.py +++ b/tests/serializers/tests.py @@ -10,6 +10,7 @@ from django.test import ( SimpleTestCase, mock, override_settings, skipUnlessDBFeature, ) from django.test.utils import Approximate +from django.utils.functional import curry from django.utils.six import StringIO from .models import ( @@ -317,3 +318,18 @@ class SerializersTransactionTestBase(object): art_obj = Article.objects.all()[0] self.assertEqual(art_obj.categories.all().count(), 1) self.assertEqual(art_obj.author.name, "Agnes") + + +def register_tests(test_class, method_name, test_func, exclude=None): + """ + Dynamically create serializer tests to ensure that all registered + serializers are automatically tested. + """ + formats = [ + f for f in serializers.get_serializer_formats() + if (not isinstance(serializers.get_serializer(f), serializers.BadSerializer) + and not f == 'geojson' + and (exclude is None or f not in exclude)) + ] + for format_ in formats: + setattr(test_class, method_name % format_, curry(test_func, format_)) diff --git a/tests/serializers_regress/models.py b/tests/serializers_regress/models.py index e781cb92c8..56c5f4f3cd 100644 --- a/tests/serializers_regress/models.py +++ b/tests/serializers_regress/models.py @@ -130,21 +130,6 @@ class Anchor(models.Model): ordering = ('id',) -class NaturalKeyAnchorManager(models.Manager): - def get_by_natural_key(self, data): - return self.get(data=data) - - -class NaturalKeyAnchor(models.Model): - objects = NaturalKeyAnchorManager() - - data = models.CharField(max_length=100, unique=True) - title = models.CharField(max_length=100, null=True) - - def natural_key(self): - return (self.data,) - - class UniqueAnchor(models.Model): """This is a model that can be used as something for other models to point at""" @@ -156,10 +141,6 @@ class FKData(models.Model): data = models.ForeignKey(Anchor, models.SET_NULL, null=True) -class FKDataNaturalKey(models.Model): - data = models.ForeignKey(NaturalKeyAnchor, models.SET_NULL, null=True) - - class M2MData(models.Model): data = models.ManyToManyField(Anchor) diff --git a/tests/serializers_regress/tests.py b/tests/serializers_regress/tests.py index e8a7aa359b..81d4a9de0e 100644 --- a/tests/serializers_regress/tests.py +++ b/tests/serializers_regress/tests.py @@ -25,11 +25,11 @@ from .models import ( BooleanData, BooleanPKData, CharData, CharPKData, ComplexModel, DateData, DateTimeData, DecimalData, DecimalPKData, EmailData, EmailPKData, ExplicitInheritBaseModel, FileData, FilePathData, FilePathPKData, FKData, - FKDataNaturalKey, FKDataToField, FKDataToO2O, FKSelfData, FKToUUID, + FKDataToField, FKDataToO2O, FKSelfData, FKToUUID, FloatData, FloatPKData, GenericData, GenericIPAddressData, GenericIPAddressPKData, InheritAbstractModel, InheritBaseModel, IntegerData, IntegerPKData, Intermediate, LengthModel, M2MData, - M2MIntermediateData, M2MSelfData, ModifyingSaveData, NaturalKeyAnchor, + M2MIntermediateData, M2MSelfData, ModifyingSaveData, NullBooleanData, O2OData, PositiveIntegerData, PositiveIntegerPKData, PositiveSmallIntegerData, PositiveSmallIntegerPKData, ProxyBaseModel, ProxyProxyBaseModel, SlugData, SlugPKData, SmallData, SmallPKData, Tag, @@ -367,11 +367,6 @@ The end."""), (data_obj, 1005, LengthModel, 1), ] -natural_key_test_data = [ - (data_obj, 1100, NaturalKeyAnchor, "Natural Key Anghor"), - (fk_obj, 1101, FKDataNaturalKey, 1100), - (fk_obj, 1102, FKDataNaturalKey, None), -] # Because Oracle treats the empty string as NULL, Oracle is expected to fail # when field.empty_strings_allowed is True and the value is None; skip these @@ -391,9 +386,6 @@ if connection.features.allows_auto_pk_0: (fk_obj, 465, FKData, 0), ]) -# Dynamically create serializer tests to ensure that all -# registered serializers are automatically tested. - @skipUnlessDBFeature('can_defer_constraint_checks') class SerializerTests(TestCase): @@ -465,36 +457,6 @@ def serializerTest(format, self): self.assertEqual(count, klass.objects.count()) -def naturalKeySerializerTest(format, self): - # Create all the objects defined in the test data - objects = [] - instance_count = {} - for (func, pk, klass, datum) in natural_key_test_data: - with connection.constraint_checks_disabled(): - objects.extend(func[0](pk, klass, datum)) - - # Get a count of the number of objects created for each class - for klass in instance_count: - instance_count[klass] = klass.objects.count() - - # Serialize the test database - serialized_data = serializers.serialize(format, objects, indent=2, - use_natural_foreign_keys=True) - - for obj in serializers.deserialize(format, serialized_data): - obj.save() - - # Assert that the deserialized data is the same - # as the original source - for (func, pk, klass, datum) in natural_key_test_data: - func[1](self, pk, klass, datum) - - # Assert that the number of objects deserialized is the - # same as the number that was serialized. - for klass, count in instance_count.items(): - self.assertEqual(count, klass.objects.count()) - - def fieldsTest(format, self): obj = ComplexModel(field1='first', field2='second', field3='third') obj.save_base(raw=True) @@ -527,39 +489,9 @@ def streamTest(format, self): self.assertEqual(string_data, stream.content.decode('utf-8')) -def naturalKeyTest(format, self): - book1 = {'data': '978-1590597255', 'title': 'The Definitive Guide to ' - 'Django: Web Development Done Right'} - book2 = {'data': '978-1590599969', 'title': 'Practical Django Projects'} - - # Create the books. - adrian = NaturalKeyAnchor.objects.create(**book1) - james = NaturalKeyAnchor.objects.create(**book2) - - # Serialize the books. - string_data = serializers.serialize(format, NaturalKeyAnchor.objects.all(), - indent=2, use_natural_foreign_keys=True, - use_natural_primary_keys=True) - - # Delete one book (to prove that the natural key generation will only - # restore the primary keys of books found in the database via the - # get_natural_key manager method). - james.delete() - - # Deserialize and test. - books = list(serializers.deserialize(format, string_data)) - self.assertEqual(len(books), 2) - self.assertEqual(books[0].object.title, book1['title']) - self.assertEqual(books[0].object.pk, adrian.pk) - self.assertEqual(books[1].object.title, book2['title']) - self.assertEqual(books[1].object.pk, None) - - for format in [f for f in serializers.get_serializer_formats() if not isinstance(serializers.get_serializer(f), serializers.BadSerializer) and not f == 'geojson']: setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format)) - setattr(SerializerTests, 'test_' + format + '_natural_key_serializer', curry(naturalKeySerializerTest, format)) setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format)) - setattr(SerializerTests, 'test_' + format + '_serializer_natural_keys', curry(naturalKeyTest, format)) if format != 'python': setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))