elytra_client/tests/test_client.py
claudi 05fca294f9 Add initial project structure and tests for Elytra PIM Client
- Created pyproject.toml for project metadata and dependencies.
- Added requirements.txt for development and production dependencies.
- Implemented basic test structure in the tests module.
- Developed unit tests for ElytraClient, including Pydantic validation and error handling.
2026-02-20 09:08:43 +01:00

178 lines
5.6 KiB
Python

"""Tests for the Elytra PIM Client with Pydantic validation"""
import pytest
from unittest.mock import Mock, patch
from pydantic import ValidationError
from elytra_client import (
ElytraClient,
SingleProductResponse,
SingleNewProductRequestBody,
)
from elytra_client.exceptions import ElytraAuthenticationError, ElytraNotFoundError
@pytest.fixture
def client():
"""Create a test client"""
return ElytraClient(
base_url="https://test.example.com/api/v1",
api_key="test-api-key",
)
def test_client_initialization(client):
"""Test client initialization"""
assert client.base_url == "https://test.example.com/api/v1"
assert client.api_key == "test-api-key"
assert client.timeout == 30
def test_client_context_manager():
"""Test client context manager"""
with ElytraClient(
base_url="https://test.example.com/api/v1",
api_key="test-api-key",
) as client:
assert client is not None
@patch("elytra_client.client.requests.Session.request")
def test_get_products_with_pydantic_validation(mock_request, client):
"""Test get_products with Pydantic validation"""
mock_response = Mock()
mock_response.json.return_value = {
"items": [
{
"id": 1,
"clientId": 231,
"productName": "Product 1",
"treeId": 0,
"created": "2025-04-08T12:00:00Z",
"modified": "2025-04-08T12:00:00Z",
"creatorUserId": 235,
"modifierUserId": 235,
"objectStatus": "original",
"originalId": 0,
"attributes": [],
}
],
"total": 1,
"page": 1,
}
mock_request.return_value = mock_response
result = client.get_products(lang="en", page=1, limit=10)
assert result["total"] == 1
assert len(result["items"]) == 1
# Items should be Pydantic models
assert isinstance(result["items"][0], SingleProductResponse)
assert result["items"][0].productName == "Product 1"
mock_request.assert_called_once()
@patch("elytra_client.client.requests.Session.request")
def test_get_product_returns_pydantic_model(mock_request, client):
"""Test get_product returns Pydantic model"""
mock_response = Mock()
mock_response.json.return_value = {
"id": 123,
"clientId": 231,
"productName": "Test Product",
"treeId": 0,
"created": "2025-04-08T12:00:00Z",
"modified": "2025-04-08T12:00:00Z",
"creatorUserId": 235,
"modifierUserId": 235,
"objectStatus": "original",
"originalId": 0,
"attributes": [],
}
mock_request.return_value = mock_response
result = client.get_product(product_id=123, lang="en")
assert isinstance(result, SingleProductResponse)
assert result.id == 123
assert result.productName == "Test Product"
@patch("elytra_client.client.requests.Session.request")
def test_create_product_with_pydantic(mock_request, client):
"""Test product creation with Pydantic validation"""
mock_response = Mock()
mock_response.json.return_value = {
"id": 999,
"clientId": 231,
"productName": "NEW-PRODUCT-001",
"treeId": 0,
"created": "2025-04-08T12:00:00Z",
"modified": "2025-04-08T12:00:00Z",
"creatorUserId": 235,
"modifierUserId": 235,
"objectStatus": "original",
"originalId": 0,
"attributes": [],
}
mock_request.return_value = mock_response
# Create with Pydantic model
new_product = SingleNewProductRequestBody(
productName="NEW-PRODUCT-001",
parentId=1,
attributeGroupId=10,
) # type: ignore - validation happens automatically, so type checker should recognize this as valid
result = client.create_product(new_product)
assert isinstance(result, SingleProductResponse)
assert result.id == 999
assert result.productName == "NEW-PRODUCT-001"
def test_pydantic_validation_on_creation():
"""Test Pydantic validation on model creation"""
# Valid model
valid_product = SingleNewProductRequestBody(
productName="VALID-PRODUCT",
parentId=1,
attributeGroupId=10,
) # type: ignore - validation happens automatically, so type checker should recognize this as valid
assert valid_product.productName == "VALID-PRODUCT"
# Invalid model - missing required field
with pytest.raises(ValidationError):
SingleNewProductRequestBody(
productName="INVALID-PRODUCT",
# Missing parentId - required
attributeGroupId=10,
) # type: ignore - this will raise a ValidationError, so type checker should recognize this as invalid
@patch("elytra_client.client.requests.Session.request")
def test_authentication_error(mock_request, client):
"""Test authentication error handling"""
mock_response = Mock()
mock_response.status_code = 401
mock_response.text = "Unauthorized"
mock_request.return_value.raise_for_status.side_effect = (
__import__("requests").exceptions.HTTPError(response=mock_response)
)
with pytest.raises(ElytraAuthenticationError):
client.get_products()
@patch("elytra_client.client.requests.Session.request")
def test_not_found_error(mock_request, client):
"""Test not found error handling"""
mock_response = Mock()
mock_response.status_code = 404
mock_response.text = "Not Found"
mock_request.return_value.raise_for_status.side_effect = (
__import__("requests").exceptions.HTTPError(response=mock_response)
)
with pytest.raises(ElytraNotFoundError):
client.get_product(product_id=999)