Added a basic benchmark suite for serializers.

This commit is contained in:
Omer Katz 2015-02-03 10:00:42 +02:00
parent 6e2ea852d0
commit 59659835e8
7 changed files with 185 additions and 38 deletions

View File

@ -5,6 +5,7 @@ Django>=1.4.11
pytest-django==2.8.0 pytest-django==2.8.0
pytest==2.6.4 pytest==2.6.4
pytest-cov==1.6 pytest-cov==1.6
pytest-bench==0.3.0
flake8==2.2.2 flake8==2.2.2
# Optional packages # Optional packages

View File

@ -8,8 +8,8 @@ import subprocess
PYTEST_ARGS = { PYTEST_ARGS = {
'default': ['tests', '--tb=short'], 'default': ['tests', '--tb=short', '--bench'],
'fast': ['tests', '--tb=short', '-q'], 'fast': ['tests', '--tb=short', '-q', '--bench'],
} }
FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501'] FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501']

10
tests/fields.py Normal file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
# coding: utf-8
from django.db import models
class CustomField(models.Field):
"""
A custom model field simply for testing purposes.
"""
pass

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .fields import CustomField
class RESTFrameworkModel(models.Model): class RESTFrameworkModel(models.Model):
@ -68,3 +69,62 @@ class NullableOneToOneSource(RESTFrameworkModel):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
target = models.OneToOneField(OneToOneTarget, null=True, blank=True, target = models.OneToOneField(OneToOneTarget, null=True, blank=True,
related_name='nullable_source') related_name='nullable_source')
class RegularFieldsModel(models.Model):
"""
A model class for testing regular flat fields.
"""
auto_field = models.AutoField(primary_key=True)
big_integer_field = models.BigIntegerField()
boolean_field = models.BooleanField(default=False)
char_field = models.CharField(max_length=100)
comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=100)
date_field = models.DateField()
datetime_field = models.DateTimeField()
decimal_field = models.DecimalField(max_digits=3, decimal_places=1)
email_field = models.EmailField(max_length=100)
float_field = models.FloatField()
integer_field = models.IntegerField()
null_boolean_field = models.NullBooleanField()
positive_integer_field = models.PositiveIntegerField()
positive_small_integer_field = models.PositiveSmallIntegerField()
slug_field = models.SlugField(max_length=100)
small_integer_field = models.SmallIntegerField()
text_field = models.TextField()
time_field = models.TimeField()
url_field = models.URLField(max_length=100)
custom_field = CustomField()
def method(self):
return 'method'
class RegularFieldsAndFKModel(models.Model):
"""
A model class for testing regular flat fields.
"""
auto_field = models.AutoField(primary_key=True)
big_integer_field = models.BigIntegerField()
boolean_field = models.BooleanField(default=False)
char_field = models.CharField(max_length=100)
comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=100)
date_field = models.DateField()
datetime_field = models.DateTimeField()
decimal_field = models.DecimalField(max_digits=3, decimal_places=1)
email_field = models.EmailField(max_length=100)
float_field = models.FloatField()
integer_field = models.IntegerField()
null_boolean_field = models.NullBooleanField()
positive_integer_field = models.PositiveIntegerField()
positive_small_integer_field = models.PositiveSmallIntegerField()
slug_field = models.SlugField(max_length=100)
small_integer_field = models.SmallIntegerField()
text_field = models.TextField()
time_field = models.TimeField()
url_field = models.URLField(max_length=100)
custom_field = CustomField()
fk = models.ForeignKey(RegularFieldsModel)
def method(self):
return 'method'

View File

@ -6,13 +6,16 @@ These tests deal with ensuring that we correctly map the model fields onto
an appropriate set of serializer fields for each case. an appropriate set of serializer fields for each case.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.validators import MaxValueValidator, MinValueValidator, MinLengthValidator from django.core.validators import MaxValueValidator, MinValueValidator, MinLengthValidator
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from django.utils import six from django.utils import six
from rest_framework import serializers from rest_framework import serializers
from rest_framework.compat import unicode_repr from rest_framework.compat import unicode_repr
from .models import RegularFieldsModel
def dedent(blocktext): def dedent(blocktext):
@ -22,46 +25,11 @@ def dedent(blocktext):
# Tests for regular field mappings. # Tests for regular field mappings.
# --------------------------------- # ---------------------------------
class CustomField(models.Field):
"""
A custom model field simply for testing purposes.
"""
pass
class OneFieldModel(models.Model): class OneFieldModel(models.Model):
char_field = models.CharField(max_length=100) char_field = models.CharField(max_length=100)
class RegularFieldsModel(models.Model):
"""
A model class for testing regular flat fields.
"""
auto_field = models.AutoField(primary_key=True)
big_integer_field = models.BigIntegerField()
boolean_field = models.BooleanField(default=False)
char_field = models.CharField(max_length=100)
comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=100)
date_field = models.DateField()
datetime_field = models.DateTimeField()
decimal_field = models.DecimalField(max_digits=3, decimal_places=1)
email_field = models.EmailField(max_length=100)
float_field = models.FloatField()
integer_field = models.IntegerField()
null_boolean_field = models.NullBooleanField()
positive_integer_field = models.PositiveIntegerField()
positive_small_integer_field = models.PositiveSmallIntegerField()
slug_field = models.SlugField(max_length=100)
small_integer_field = models.SmallIntegerField()
text_field = models.TextField()
time_field = models.TimeField()
url_field = models.URLField(max_length=100)
custom_field = CustomField()
def method(self):
return 'method'
COLOR_CHOICES = (('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')) COLOR_CHOICES = (('red', 'Red'), ('blue', 'Blue'), ('green', 'Green'))
@ -125,7 +93,7 @@ class TestRegularFieldMappings(TestCase):
text_field = CharField(style={'base_template': 'textarea.html'}) text_field = CharField(style={'base_template': 'textarea.html'})
time_field = TimeField() time_field = TimeField()
url_field = URLField(max_length=100) url_field = URLField(max_length=100)
custom_field = ModelField(model_field=<tests.test_model_serializer.CustomField: custom_field>) custom_field = ModelField(model_field=<tests.fields.CustomField: custom_field>)
""") """)
self.assertEqual(unicode_repr(TestSerializer()), expected) self.assertEqual(unicode_repr(TestSerializer()), expected)

View File

@ -0,0 +1,107 @@
from decimal import Decimal
from pytest import mark
from datetime import datetime
from rest_framework import serializers
from .models import RegularFieldsModel, RegularFieldsAndFKModel
data = {
'big_integer_field': 100000,
'char_field': 'a',
'comma_separated_integer_field': '1,2',
'date_field': datetime.now().date(),
'datetime_field': datetime.now(),
'decimal_field': Decimal('1.5'),
'email_field': 'somewhere@overtherainbow.com',
'float_field': 0.443,
'integer_field': 55,
'null_boolean_field': True,
'positive_integer_field': 1,
'positive_small_integer_field': 1,
'slug_field': 'slug-friendly-text',
'small_integer_field': 1,
'text_field': 'lorem ipsum',
'time_field': datetime.now().time(),
'url_field': 'https://overtherainbow.com'
}
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RegularFieldsModel
fields = data.keys() + ['method']
class TestNestedSerializer(serializers.ModelSerializer):
fk = TestSerializer()
class Meta:
model = RegularFieldsAndFKModel
fields = data.keys() + ['method', 'fk']
@mark.bench('serializers.ModelSerializer.to_representation')
def test_object_serialization():
instance = RegularFieldsModel(**data)
serializer = TestSerializer(instance=instance)
assert serializer.data, serializer.errors
@mark.bench('serializers.ModelSerializer.to_representation')
def test_nested_object_serialization():
nested_instance = RegularFieldsModel(**data)
instance = RegularFieldsAndFKModel(fk=nested_instance, **data)
serializer = TestSerializer(instance=instance)
assert serializer.data, serializer.errors
@mark.bench('serializers.ModelSerializer.to_representation')
def test_object_list_serialization():
instance = [RegularFieldsModel(**data) for _ in range(100)]
serializer = TestSerializer(instance=instance, many=True)
assert serializer.data, serializer.errors
@mark.bench('serializers.ModelSerializer.to_representation')
def test_object_serialization_with_partial_update():
instance = RegularFieldsModel(**data)
serializer = TestSerializer(instance=instance, data={'char_field': 'b'}, partial=True)
assert serializer.is_valid(), serializer.errors
assert serializer.data, serializer.errors
@mark.bench('serializers.ModelSerializer.to_representation')
def test_object_serialization_with_update():
instance = RegularFieldsModel(**data)
new_data = data.copy()
new_data['char_field'] = 'b'
serializer = TestSerializer(instance=instance, data=new_data)
assert serializer.is_valid(), serializer.errors
assert serializer.data, serializer.errors
@mark.bench('serializers.ModelSerializer.to_internal_value')
def test_object_deserialization():
serializer = TestSerializer(data=data)
assert serializer.is_valid(), serializer.errors
@mark.bench('serializers.ModelSerializer.to_internal_value')
def test_object_list_deserialization():
serializer = TestSerializer(data=[data for _ in range(100)], many=True)
assert serializer.is_valid(), serializer.errors
@mark.bench('serializers.ModelSerializer.__init__')
def test_serializer_initialization():
TestSerializer(data=data)

View File

@ -22,6 +22,7 @@ deps =
{py26,py27}-django{14,15}: django-oauth2-provider==0.2.3 {py26,py27}-django{14,15}: django-oauth2-provider==0.2.3
{py26,py27}-django16: django-oauth2-provider==0.2.4 {py26,py27}-django16: django-oauth2-provider==0.2.4
pytest-django==2.8.0 pytest-django==2.8.0
pytest-bench==0.3.0
django-filter==0.9.2 django-filter==0.9.2
defusedxml==0.3 defusedxml==0.3
markdown>=2.1.0 markdown>=2.1.0