init project tests
This commit is contained in:
parent
d0ff728224
commit
7c9318c778
44 changed files with 4431 additions and 49 deletions
262
test/unit/test_costs_models.py
Normal file
262
test/unit/test_costs_models.py
Normal file
|
@ -0,0 +1,262 @@
|
|||
"""
|
||||
Unit tests for Costs models.
|
||||
"""
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from decimal import Decimal
|
||||
|
||||
from costs.models import Costs
|
||||
from bird.models import Bird, BirdStatus, Circumstance
|
||||
from aviary.models import Aviary
|
||||
|
||||
|
||||
class CostsModelTests(TestCase):
|
||||
"""Test cases for Costs model."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
self.user = User.objects.create_user(
|
||||
username='testuser',
|
||||
email='test@example.com',
|
||||
password='testpass123'
|
||||
)
|
||||
|
||||
self.aviary = Aviary.objects.create(
|
||||
name="Test Aviary",
|
||||
location="Test Location",
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
self.bird_status = BirdStatus.objects.create(
|
||||
name="Gesund",
|
||||
description="Healthy bird"
|
||||
)
|
||||
|
||||
self.circumstance = Circumstance.objects.create(
|
||||
name="Gefunden",
|
||||
description="Found bird"
|
||||
)
|
||||
|
||||
self.bird = Bird.objects.create(
|
||||
name="Test Bird",
|
||||
species="Test Species",
|
||||
aviary=self.aviary,
|
||||
status=self.bird_status,
|
||||
circumstance=self.circumstance,
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
self.costs = Costs.objects.create(
|
||||
bird=self.bird,
|
||||
description="Veterinary treatment",
|
||||
amount=Decimal('150.75'),
|
||||
cost_date=timezone.now().date(),
|
||||
category="medical",
|
||||
invoice_number="INV-001",
|
||||
vendor="Test Veterinary Clinic",
|
||||
notes="Routine checkup and treatment",
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
def test_costs_creation(self):
|
||||
"""Test that a cost entry can be created."""
|
||||
self.assertTrue(isinstance(self.costs, Costs))
|
||||
self.assertEqual(self.costs.bird, self.bird)
|
||||
self.assertEqual(self.costs.description, "Veterinary treatment")
|
||||
self.assertEqual(self.costs.amount, Decimal('150.75'))
|
||||
self.assertEqual(self.costs.category, "medical")
|
||||
self.assertEqual(self.costs.invoice_number, "INV-001")
|
||||
self.assertEqual(self.costs.vendor, "Test Veterinary Clinic")
|
||||
self.assertEqual(self.costs.notes, "Routine checkup and treatment")
|
||||
|
||||
def test_costs_str_representation(self):
|
||||
"""Test the string representation of costs."""
|
||||
expected = f"{self.costs.description} - €{self.costs.amount}"
|
||||
self.assertEqual(str(self.costs), expected)
|
||||
|
||||
def test_costs_amount_validation(self):
|
||||
"""Test that cost amount is validated."""
|
||||
# Test negative amount
|
||||
with self.assertRaises(ValidationError):
|
||||
costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Invalid cost",
|
||||
amount=Decimal('-10.00'),
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
costs.full_clean()
|
||||
|
||||
# Test zero amount (should be valid)
|
||||
costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Zero cost",
|
||||
amount=Decimal('0.00'),
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
costs.full_clean() # Should not raise validation error
|
||||
|
||||
def test_costs_category_choices(self):
|
||||
"""Test that cost category has valid choices."""
|
||||
valid_categories = ['medical', 'food', 'equipment', 'transport', 'other']
|
||||
self.assertIn(self.costs.category, valid_categories)
|
||||
|
||||
# Test invalid category
|
||||
with self.assertRaises(ValidationError):
|
||||
costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Invalid category",
|
||||
amount=Decimal('10.00'),
|
||||
category="invalid_category",
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
costs.full_clean()
|
||||
|
||||
def test_costs_required_fields(self):
|
||||
"""Test that required fields are validated."""
|
||||
with self.assertRaises(ValidationError):
|
||||
costs = Costs()
|
||||
costs.full_clean()
|
||||
|
||||
def test_costs_relationship(self):
|
||||
"""Test costs relationships."""
|
||||
self.assertEqual(self.costs.bird, self.bird)
|
||||
self.assertEqual(self.costs.created_by, self.user)
|
||||
|
||||
def test_costs_date_validation(self):
|
||||
"""Test that cost date is validated."""
|
||||
# Test future date (should be valid unless restricted)
|
||||
future_date = timezone.now().date() + timezone.timedelta(days=30)
|
||||
costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Future cost",
|
||||
amount=Decimal('50.00'),
|
||||
cost_date=future_date,
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
costs.full_clean() # Should not raise validation error
|
||||
|
||||
def test_costs_decimal_precision(self):
|
||||
"""Test decimal precision for amounts."""
|
||||
# Test 2 decimal place amount (model allows max 2 decimal places)
|
||||
precise_amount = Decimal('123.45')
|
||||
costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Precise amount",
|
||||
amount=precise_amount,
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
costs.full_clean()
|
||||
costs.save()
|
||||
|
||||
# Reload from database and check precision
|
||||
costs.refresh_from_db()
|
||||
# Model supports 2 decimal places, should match exactly
|
||||
self.assertEqual(costs.amount, precise_amount)
|
||||
|
||||
# Test that amounts with more than 2 decimal places are rejected
|
||||
with self.assertRaises(ValidationError):
|
||||
invalid_costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Too precise amount",
|
||||
amount=Decimal('123.456'), # More than 2 decimal places
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
invalid_costs.full_clean()
|
||||
|
||||
def test_costs_filtering_by_category(self):
|
||||
"""Test filtering costs by category."""
|
||||
# Create costs in different categories
|
||||
Costs.objects.create(
|
||||
bird=self.bird,
|
||||
description="Food cost",
|
||||
amount=Decimal('25.00'),
|
||||
category="food",
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
Costs.objects.create(
|
||||
bird=self.bird,
|
||||
description="Equipment cost",
|
||||
amount=Decimal('75.00'),
|
||||
category="equipment",
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
# Filter by category
|
||||
medical_costs = Costs.objects.filter(category="medical")
|
||||
food_costs = Costs.objects.filter(category="food")
|
||||
equipment_costs = Costs.objects.filter(category="equipment")
|
||||
|
||||
self.assertEqual(medical_costs.count(), 1)
|
||||
self.assertEqual(food_costs.count(), 1)
|
||||
self.assertEqual(equipment_costs.count(), 1)
|
||||
|
||||
self.assertIn(self.costs, medical_costs)
|
||||
|
||||
def test_costs_total_for_bird(self):
|
||||
"""Test calculating total costs for a bird."""
|
||||
# Create additional costs for the same bird
|
||||
Costs.objects.create(
|
||||
bird=self.bird,
|
||||
description="Additional cost 1",
|
||||
amount=Decimal('50.00'),
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
Costs.objects.create(
|
||||
bird=self.bird,
|
||||
description="Additional cost 2",
|
||||
amount=Decimal('25.25'),
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
|
||||
# Calculate total costs for the bird
|
||||
total_costs = Costs.objects.filter(bird=self.bird).aggregate(
|
||||
total=models.Sum('amount')
|
||||
)['total']
|
||||
|
||||
expected_total = Decimal('150.75') + Decimal('50.00') + Decimal('25.25')
|
||||
self.assertEqual(total_costs, expected_total)
|
||||
|
||||
def test_costs_invoice_number_uniqueness(self):
|
||||
"""Test invoice number uniqueness if enforced."""
|
||||
# Try to create another cost with the same invoice number
|
||||
try:
|
||||
duplicate_costs = Costs(
|
||||
bird=self.bird,
|
||||
description="Duplicate invoice",
|
||||
amount=Decimal('10.00'),
|
||||
invoice_number="INV-001", # Same as self.costs
|
||||
cost_date=timezone.now().date(),
|
||||
user=self.user,
|
||||
created_by=self.user
|
||||
)
|
||||
duplicate_costs.full_clean()
|
||||
# If unique constraint exists, this should fail
|
||||
except ValidationError:
|
||||
# Expected if invoice_number has unique constraint
|
||||
pass
|
Loading…
Add table
Add a link
Reference in a new issue