mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-21 02:31:08 -05:00
Add comprehensive tests for Parks API and models
- Implemented extensive test cases for the Parks API, covering endpoints for listing, retrieving, creating, updating, and deleting parks. - Added tests for filtering, searching, and ordering parks in the API. - Created tests for error handling in the API, including malformed JSON and unsupported methods. - Developed model tests for Park, ParkArea, Company, and ParkReview models, ensuring validation and constraints are enforced. - Introduced utility mixins for API and model testing to streamline assertions and enhance test readability. - Included integration tests to validate complete workflows involving park creation, retrieval, updating, and deletion.
This commit is contained in:
349
rides/api/serializers.py
Normal file
349
rides/api/serializers.py
Normal file
@@ -0,0 +1,349 @@
|
||||
"""
|
||||
Serializers for Rides API following Django styleguide patterns.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from ..models import Ride, RideModel, Company
|
||||
|
||||
|
||||
class RideModelOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for ride model data."""
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
category = serializers.CharField()
|
||||
manufacturer = serializers.SerializerMethodField()
|
||||
|
||||
def get_manufacturer(self, obj):
|
||||
if obj.manufacturer:
|
||||
return {
|
||||
'id': obj.manufacturer.id,
|
||||
'name': obj.manufacturer.name,
|
||||
'slug': obj.manufacturer.slug
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
class RideParkOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for ride's park data."""
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
|
||||
|
||||
class RideListOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for ride list view."""
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
category = serializers.CharField()
|
||||
status = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
|
||||
# Park info
|
||||
park = RideParkOutputSerializer()
|
||||
|
||||
# Statistics
|
||||
average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True)
|
||||
capacity_per_hour = serializers.IntegerField(allow_null=True)
|
||||
|
||||
# Dates
|
||||
opening_date = serializers.DateField(allow_null=True)
|
||||
closing_date = serializers.DateField(allow_null=True)
|
||||
|
||||
# Metadata
|
||||
created_at = serializers.DateTimeField()
|
||||
updated_at = serializers.DateTimeField()
|
||||
|
||||
|
||||
class RideDetailOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for ride detail view."""
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
category = serializers.CharField()
|
||||
status = serializers.CharField()
|
||||
post_closing_status = serializers.CharField(allow_null=True)
|
||||
description = serializers.CharField()
|
||||
|
||||
# Park info
|
||||
park = RideParkOutputSerializer()
|
||||
park_area = serializers.SerializerMethodField()
|
||||
|
||||
# Dates
|
||||
opening_date = serializers.DateField(allow_null=True)
|
||||
closing_date = serializers.DateField(allow_null=True)
|
||||
status_since = serializers.DateField(allow_null=True)
|
||||
|
||||
# Physical specs
|
||||
min_height_in = serializers.IntegerField(allow_null=True)
|
||||
max_height_in = serializers.IntegerField(allow_null=True)
|
||||
capacity_per_hour = serializers.IntegerField(allow_null=True)
|
||||
ride_duration_seconds = serializers.IntegerField(allow_null=True)
|
||||
|
||||
# Statistics
|
||||
average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True)
|
||||
|
||||
# Companies
|
||||
manufacturer = serializers.SerializerMethodField()
|
||||
designer = serializers.SerializerMethodField()
|
||||
|
||||
# Model
|
||||
ride_model = RideModelOutputSerializer(allow_null=True)
|
||||
|
||||
# Metadata
|
||||
created_at = serializers.DateTimeField()
|
||||
updated_at = serializers.DateTimeField()
|
||||
|
||||
def get_park_area(self, obj):
|
||||
if obj.park_area:
|
||||
return {
|
||||
'id': obj.park_area.id,
|
||||
'name': obj.park_area.name,
|
||||
'slug': obj.park_area.slug
|
||||
}
|
||||
return None
|
||||
|
||||
def get_manufacturer(self, obj):
|
||||
if obj.manufacturer:
|
||||
return {
|
||||
'id': obj.manufacturer.id,
|
||||
'name': obj.manufacturer.name,
|
||||
'slug': obj.manufacturer.slug
|
||||
}
|
||||
return None
|
||||
|
||||
def get_designer(self, obj):
|
||||
if obj.designer:
|
||||
return {
|
||||
'id': obj.designer.id,
|
||||
'name': obj.designer.name,
|
||||
'slug': obj.designer.slug
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
class RideCreateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for creating rides."""
|
||||
name = serializers.CharField(max_length=255)
|
||||
description = serializers.CharField(allow_blank=True, default="")
|
||||
category = serializers.ChoiceField(choices=Ride.CATEGORY_CHOICES)
|
||||
status = serializers.ChoiceField(
|
||||
choices=Ride.STATUS_CHOICES,
|
||||
default="OPERATING"
|
||||
)
|
||||
|
||||
# Required park
|
||||
park_id = serializers.IntegerField()
|
||||
|
||||
# Optional area
|
||||
park_area_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
# Optional dates
|
||||
opening_date = serializers.DateField(required=False, allow_null=True)
|
||||
closing_date = serializers.DateField(required=False, allow_null=True)
|
||||
status_since = serializers.DateField(required=False, allow_null=True)
|
||||
|
||||
# Optional specs
|
||||
min_height_in = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=30,
|
||||
max_value=90
|
||||
)
|
||||
max_height_in = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=30,
|
||||
max_value=90
|
||||
)
|
||||
capacity_per_hour = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=1
|
||||
)
|
||||
ride_duration_seconds = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=1
|
||||
)
|
||||
|
||||
# Optional companies
|
||||
manufacturer_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
designer_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
# Optional model
|
||||
ride_model_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
def validate(self, data):
|
||||
"""Cross-field validation."""
|
||||
# Date validation
|
||||
opening_date = data.get('opening_date')
|
||||
closing_date = data.get('closing_date')
|
||||
|
||||
if opening_date and closing_date and closing_date < opening_date:
|
||||
raise serializers.ValidationError(
|
||||
"Closing date cannot be before opening date"
|
||||
)
|
||||
|
||||
# Height validation
|
||||
min_height = data.get('min_height_in')
|
||||
max_height = data.get('max_height_in')
|
||||
|
||||
if min_height and max_height and min_height > max_height:
|
||||
raise serializers.ValidationError(
|
||||
"Minimum height cannot be greater than maximum height"
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class RideUpdateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for updating rides."""
|
||||
name = serializers.CharField(max_length=255, required=False)
|
||||
description = serializers.CharField(allow_blank=True, required=False)
|
||||
category = serializers.ChoiceField(choices=Ride.CATEGORY_CHOICES, required=False)
|
||||
status = serializers.ChoiceField(choices=Ride.STATUS_CHOICES, required=False)
|
||||
post_closing_status = serializers.ChoiceField(
|
||||
choices=Ride.POST_CLOSING_STATUS_CHOICES,
|
||||
required=False,
|
||||
allow_null=True
|
||||
)
|
||||
|
||||
# Park and area
|
||||
park_id = serializers.IntegerField(required=False)
|
||||
park_area_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
# Dates
|
||||
opening_date = serializers.DateField(required=False, allow_null=True)
|
||||
closing_date = serializers.DateField(required=False, allow_null=True)
|
||||
status_since = serializers.DateField(required=False, allow_null=True)
|
||||
|
||||
# Specs
|
||||
min_height_in = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=30,
|
||||
max_value=90
|
||||
)
|
||||
max_height_in = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=30,
|
||||
max_value=90
|
||||
)
|
||||
capacity_per_hour = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=1
|
||||
)
|
||||
ride_duration_seconds = serializers.IntegerField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
min_value=1
|
||||
)
|
||||
|
||||
# Companies
|
||||
manufacturer_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
designer_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
# Model
|
||||
ride_model_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
def validate(self, data):
|
||||
"""Cross-field validation."""
|
||||
# Date validation
|
||||
opening_date = data.get('opening_date')
|
||||
closing_date = data.get('closing_date')
|
||||
|
||||
if opening_date and closing_date and closing_date < opening_date:
|
||||
raise serializers.ValidationError(
|
||||
"Closing date cannot be before opening date"
|
||||
)
|
||||
|
||||
# Height validation
|
||||
min_height = data.get('min_height_in')
|
||||
max_height = data.get('max_height_in')
|
||||
|
||||
if min_height and max_height and min_height > max_height:
|
||||
raise serializers.ValidationError(
|
||||
"Minimum height cannot be greater than maximum height"
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class RideFilterInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for ride filtering and search."""
|
||||
# Search
|
||||
search = serializers.CharField(required=False, allow_blank=True)
|
||||
|
||||
# Category filter
|
||||
category = serializers.MultipleChoiceField(
|
||||
choices=Ride.CATEGORY_CHOICES,
|
||||
required=False
|
||||
)
|
||||
|
||||
# Status filter
|
||||
status = serializers.MultipleChoiceField(
|
||||
choices=Ride.STATUS_CHOICES,
|
||||
required=False
|
||||
)
|
||||
|
||||
# Park filter
|
||||
park_id = serializers.IntegerField(required=False)
|
||||
park_slug = serializers.CharField(required=False, allow_blank=True)
|
||||
|
||||
# Company filters
|
||||
manufacturer_id = serializers.IntegerField(required=False)
|
||||
designer_id = serializers.IntegerField(required=False)
|
||||
|
||||
# Rating filter
|
||||
min_rating = serializers.DecimalField(
|
||||
max_digits=3,
|
||||
decimal_places=2,
|
||||
required=False,
|
||||
min_value=1,
|
||||
max_value=10
|
||||
)
|
||||
|
||||
# Height filters
|
||||
min_height_requirement = serializers.IntegerField(required=False)
|
||||
max_height_requirement = serializers.IntegerField(required=False)
|
||||
|
||||
# Capacity filter
|
||||
min_capacity = serializers.IntegerField(required=False)
|
||||
|
||||
# Ordering
|
||||
ordering = serializers.ChoiceField(
|
||||
choices=[
|
||||
'name', '-name',
|
||||
'opening_date', '-opening_date',
|
||||
'average_rating', '-average_rating',
|
||||
'capacity_per_hour', '-capacity_per_hour',
|
||||
'created_at', '-created_at'
|
||||
],
|
||||
required=False,
|
||||
default='name'
|
||||
)
|
||||
|
||||
|
||||
class RideStatsOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for ride statistics."""
|
||||
total_rides = serializers.IntegerField()
|
||||
operating_rides = serializers.IntegerField()
|
||||
closed_rides = serializers.IntegerField()
|
||||
under_construction = serializers.IntegerField()
|
||||
|
||||
# By category
|
||||
rides_by_category = serializers.DictField()
|
||||
|
||||
# Averages
|
||||
average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True)
|
||||
average_capacity = serializers.DecimalField(max_digits=8, decimal_places=2, allow_null=True)
|
||||
|
||||
# Top manufacturers
|
||||
top_manufacturers = serializers.ListField(child=serializers.DictField())
|
||||
|
||||
# Recently added
|
||||
recently_added_count = serializers.IntegerField()
|
||||
Reference in New Issue
Block a user