refactor: split database model tests into organized modules
Split the monolithic test_database_models.py into focused test modules: Database model tests (tests/unit/models/database/): - test_customer.py: Customer model and authentication tests - test_inventory.py: Inventory model tests - test_marketplace_import_job.py: Import job model tests - test_marketplace_product.py: Marketplace product model tests - test_order.py: Order and OrderItem model tests - test_product.py: Product model tests - test_team.py: Team invitation and membership tests - test_user.py: User model tests - test_vendor.py: Vendor model tests Schema validation tests (tests/unit/models/schema/): - test_auth.py: Auth schema validation tests - test_customer.py: Customer schema validation tests - test_inventory.py: Inventory schema validation tests - test_marketplace_import_job.py: Import job schema tests - test_order.py: Order schema validation tests - test_product.py: Product schema validation tests This improves test organization and makes it easier to find and maintain tests for specific models. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
243
tests/unit/models/schema/test_product.py
Normal file
243
tests/unit/models/schema/test_product.py
Normal file
@@ -0,0 +1,243 @@
|
||||
# tests/unit/models/schema/test_product.py
|
||||
"""Unit tests for product Pydantic schemas."""
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from models.schema.product import (
|
||||
ProductCreate,
|
||||
ProductUpdate,
|
||||
ProductResponse,
|
||||
ProductDetailResponse,
|
||||
ProductListResponse,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.schema
|
||||
class TestProductCreateSchema:
|
||||
"""Test ProductCreate schema validation."""
|
||||
|
||||
def test_valid_product_create(self):
|
||||
"""Test valid product creation data."""
|
||||
product = ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
product_id="SKU-001",
|
||||
price=99.99,
|
||||
currency="EUR",
|
||||
)
|
||||
assert product.marketplace_product_id == 1
|
||||
assert product.product_id == "SKU-001"
|
||||
assert product.price == 99.99
|
||||
|
||||
def test_marketplace_product_id_required(self):
|
||||
"""Test marketplace_product_id is required."""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
ProductCreate(price=99.99)
|
||||
assert "marketplace_product_id" in str(exc_info.value).lower()
|
||||
|
||||
def test_price_must_be_non_negative(self):
|
||||
"""Test price must be >= 0."""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
price=-10.00,
|
||||
)
|
||||
assert "price" in str(exc_info.value).lower()
|
||||
|
||||
def test_price_zero_is_valid(self):
|
||||
"""Test price of 0 is valid."""
|
||||
product = ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
price=0,
|
||||
)
|
||||
assert product.price == 0
|
||||
|
||||
def test_sale_price_must_be_non_negative(self):
|
||||
"""Test sale_price must be >= 0."""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
sale_price=-5.00,
|
||||
)
|
||||
assert "sale_price" in str(exc_info.value).lower()
|
||||
|
||||
def test_min_quantity_default(self):
|
||||
"""Test min_quantity defaults to 1."""
|
||||
product = ProductCreate(marketplace_product_id=1)
|
||||
assert product.min_quantity == 1
|
||||
|
||||
def test_min_quantity_must_be_at_least_1(self):
|
||||
"""Test min_quantity must be >= 1."""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
min_quantity=0,
|
||||
)
|
||||
assert "min_quantity" in str(exc_info.value).lower()
|
||||
|
||||
def test_max_quantity_must_be_at_least_1(self):
|
||||
"""Test max_quantity must be >= 1 if provided."""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
max_quantity=0,
|
||||
)
|
||||
assert "max_quantity" in str(exc_info.value).lower()
|
||||
|
||||
def test_is_featured_default(self):
|
||||
"""Test is_featured defaults to False."""
|
||||
product = ProductCreate(marketplace_product_id=1)
|
||||
assert product.is_featured is False
|
||||
|
||||
def test_all_optional_fields(self):
|
||||
"""Test product with all optional fields."""
|
||||
product = ProductCreate(
|
||||
marketplace_product_id=1,
|
||||
product_id="SKU-001",
|
||||
price=100.00,
|
||||
sale_price=80.00,
|
||||
currency="EUR",
|
||||
availability="in_stock",
|
||||
condition="new",
|
||||
is_featured=True,
|
||||
min_quantity=2,
|
||||
max_quantity=10,
|
||||
)
|
||||
assert product.sale_price == 80.00
|
||||
assert product.availability == "in_stock"
|
||||
assert product.condition == "new"
|
||||
assert product.is_featured is True
|
||||
assert product.max_quantity == 10
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.schema
|
||||
class TestProductUpdateSchema:
|
||||
"""Test ProductUpdate schema validation."""
|
||||
|
||||
def test_partial_update(self):
|
||||
"""Test partial update with only some fields."""
|
||||
update = ProductUpdate(price=150.00)
|
||||
assert update.price == 150.00
|
||||
assert update.product_id is None
|
||||
assert update.is_active is None
|
||||
|
||||
def test_empty_update_is_valid(self):
|
||||
"""Test empty update is valid (all fields optional)."""
|
||||
update = ProductUpdate()
|
||||
assert update.model_dump(exclude_unset=True) == {}
|
||||
|
||||
def test_price_validation(self):
|
||||
"""Test price must be >= 0 in update."""
|
||||
with pytest.raises(ValidationError):
|
||||
ProductUpdate(price=-10.00)
|
||||
|
||||
def test_is_active_update(self):
|
||||
"""Test is_active can be updated."""
|
||||
update = ProductUpdate(is_active=False)
|
||||
assert update.is_active is False
|
||||
|
||||
def test_is_featured_update(self):
|
||||
"""Test is_featured can be updated."""
|
||||
update = ProductUpdate(is_featured=True)
|
||||
assert update.is_featured is True
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.schema
|
||||
class TestProductResponseSchema:
|
||||
"""Test ProductResponse schema."""
|
||||
|
||||
def test_from_dict(self):
|
||||
"""Test creating response from dict."""
|
||||
from datetime import datetime
|
||||
|
||||
data = {
|
||||
"id": 1,
|
||||
"vendor_id": 1,
|
||||
"marketplace_product": {
|
||||
"id": 1,
|
||||
"gtin": "1234567890123",
|
||||
"title": "Test Product",
|
||||
"description": "A test product",
|
||||
"brand": "Test Brand",
|
||||
"category": "Electronics",
|
||||
"image_url": "https://example.com/image.jpg",
|
||||
"created_at": datetime.now(),
|
||||
"updated_at": datetime.now(),
|
||||
},
|
||||
"product_id": "SKU-001",
|
||||
"price": 99.99,
|
||||
"sale_price": None,
|
||||
"currency": "EUR",
|
||||
"availability": "in_stock",
|
||||
"condition": "new",
|
||||
"is_featured": False,
|
||||
"is_active": True,
|
||||
"display_order": 0,
|
||||
"min_quantity": 1,
|
||||
"max_quantity": None,
|
||||
"created_at": datetime.now(),
|
||||
"updated_at": datetime.now(),
|
||||
}
|
||||
response = ProductResponse(**data)
|
||||
assert response.id == 1
|
||||
assert response.vendor_id == 1
|
||||
assert response.is_active is True
|
||||
|
||||
def test_optional_inventory_fields(self):
|
||||
"""Test optional inventory summary fields."""
|
||||
from datetime import datetime
|
||||
|
||||
data = {
|
||||
"id": 1,
|
||||
"vendor_id": 1,
|
||||
"marketplace_product": {
|
||||
"id": 1,
|
||||
"gtin": "1234567890123",
|
||||
"title": "Test Product",
|
||||
"description": None,
|
||||
"brand": None,
|
||||
"category": None,
|
||||
"image_url": None,
|
||||
"created_at": datetime.now(),
|
||||
"updated_at": datetime.now(),
|
||||
},
|
||||
"product_id": None,
|
||||
"price": None,
|
||||
"sale_price": None,
|
||||
"currency": None,
|
||||
"availability": None,
|
||||
"condition": None,
|
||||
"is_featured": False,
|
||||
"is_active": True,
|
||||
"display_order": 0,
|
||||
"min_quantity": 1,
|
||||
"max_quantity": None,
|
||||
"created_at": datetime.now(),
|
||||
"updated_at": datetime.now(),
|
||||
"total_inventory": 100,
|
||||
"available_inventory": 80,
|
||||
}
|
||||
response = ProductResponse(**data)
|
||||
assert response.total_inventory == 100
|
||||
assert response.available_inventory == 80
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.schema
|
||||
class TestProductListResponseSchema:
|
||||
"""Test ProductListResponse schema."""
|
||||
|
||||
def test_valid_list_response(self):
|
||||
"""Test valid list response structure."""
|
||||
response = ProductListResponse(
|
||||
products=[],
|
||||
total=0,
|
||||
skip=0,
|
||||
limit=10,
|
||||
)
|
||||
assert response.products == []
|
||||
assert response.total == 0
|
||||
assert response.skip == 0
|
||||
assert response.limit == 10
|
||||
Reference in New Issue
Block a user