muryshev's picture
update
744a170
raw
history blame
11.4 kB
"""
Unit-тесты для базового класса LinkerEntity и его механизма сериализации/десериализации.
"""
import uuid
from dataclasses import dataclass, field
from uuid import UUID, uuid4
import pytest
from ntr_text_fragmentation.models import LinkerEntity, register_entity
from tests.custom_entity import \
CustomEntity # Используем существующий кастомный класс
# Фикстуры
@pytest.fixture
def base_entity() -> LinkerEntity:
"""Фикстура для базовой сущности."""
return LinkerEntity(id=uuid4(), name="Base Name", text="Base Text")
@pytest.fixture
def link_entity() -> LinkerEntity:
"""Фикстура для сущности-связи."""
return LinkerEntity(
id=uuid4(),
name="Link Name",
source_id=uuid4(),
target_id=uuid4(),
number_in_relation=1,
)
@pytest.fixture
def custom_entity_instance() -> CustomEntity:
"""Фикстура для кастомной сущности."""
return CustomEntity(
id=uuid4(),
name="Custom Name",
text="Custom Text",
custom_field="custom_value",
metadata={"existing_meta": "meta_value"},
)
@pytest.fixture
def serialized_custom_entity(
custom_entity_instance: CustomEntity,
) -> LinkerEntity:
"""Фикстура для сериализованной кастомной сущности."""
return custom_entity_instance.serialize()
# Тесты
class TestLinkerEntity:
"""Тесты для класса LinkerEntity."""
def test_initialization_defaults(self):
"""Тест инициализации с значениями по умолчанию."""
entity = LinkerEntity()
assert isinstance(entity.id, UUID)
assert entity.name == ""
assert entity.text == ""
assert entity.metadata == {}
assert entity.in_search_text is None
assert entity.source_id is None
assert entity.target_id is None
assert entity.number_in_relation is None
assert entity.groupper is None
assert entity.type == "LinkerEntity" # Имя класса по умолчанию
def test_initialization_with_values(self, base_entity: LinkerEntity):
"""Тест инициализации с заданными значениями."""
entity_id = base_entity.id
assert base_entity.name == "Base Name"
assert base_entity.text == "Base Text"
assert base_entity.id == entity_id
def test_is_link(self, base_entity: LinkerEntity, link_entity: LinkerEntity):
"""Тест метода is_link()."""
assert not base_entity.is_link()
assert link_entity.is_link()
def test_owner_id_property(self, base_entity: LinkerEntity, link_entity: LinkerEntity):
"""Тест свойства owner_id."""
# У обычной сущности owner_id это target_id
owner_uuid = uuid4()
base_entity.target_id = owner_uuid
assert base_entity.owner_id == owner_uuid
# У связи нет owner_id
assert link_entity.owner_id is None
# Попытка установить owner_id для связи должна вызвать ошибку
with pytest.raises(ValueError, match="Связь не может иметь владельца"):
link_entity.owner_id = uuid4()
# Установка owner_id для обычной сущности
new_owner_id = uuid4()
base_entity.owner_id = new_owner_id
assert base_entity.target_id == new_owner_id
def test_str_representation(self, base_entity: LinkerEntity):
"""Тест строкового представления __str__."""
assert str(base_entity) == "Base Name: Base Text"
base_entity.in_search_text = "Search text representation"
assert str(base_entity) == "Search text representation"
def test_equality(self, base_entity: LinkerEntity):
"""Тест сравнения __eq__."""
entity_copy = LinkerEntity(
id=base_entity.id, name="Base Name", text="Base Text"
)
different_entity = LinkerEntity(name="Different Name")
assert base_entity == entity_copy
assert base_entity != different_entity
assert base_entity != "not an entity"
def test_equality_links(self, link_entity: LinkerEntity):
"""Тест сравнения связей."""
link_copy = LinkerEntity(
id=link_entity.id,
name="Link Name",
source_id=link_entity.source_id,
target_id=link_entity.target_id,
number_in_relation=1,
)
different_link = LinkerEntity(
id=link_entity.id,
name="Link Name",
source_id=uuid4(), # Другой source_id
target_id=link_entity.target_id,
number_in_relation=1,
)
non_link = LinkerEntity(id=link_entity.id)
assert link_entity == link_copy
assert link_entity != different_link
assert link_entity != non_link
# --- Тесты сериализации/десериализации ---
def test_serialize_base_entity(self, base_entity: LinkerEntity):
"""Тест сериализации базовой сущности."""
serialized = base_entity.serialize()
assert isinstance(serialized, LinkerEntity)
# Проверяем, что это не тот же самый объект, а копия базового типа
assert serialized is not base_entity
assert type(serialized) is LinkerEntity
assert serialized.id == base_entity.id
assert serialized.name == base_entity.name
assert serialized.text == base_entity.text
assert serialized.metadata == {} # Нет доп. полей
assert serialized.type == "LinkerEntity" # Сохраняем тип
def test_serialize_custom_entity(
self,
custom_entity_instance: CustomEntity,
serialized_custom_entity: LinkerEntity,
):
"""Тест сериализации кастомной сущности."""
serialized = serialized_custom_entity # Используем фикстуру
assert isinstance(serialized, LinkerEntity)
assert type(serialized) is LinkerEntity
assert serialized.id == custom_entity_instance.id
assert serialized.name == custom_entity_instance.name
assert serialized.text == custom_entity_instance.text
# Проверяем, что кастомное поле и исходные метаданные попали в metadata
assert "_custom_field" in serialized.metadata
assert serialized.metadata["_custom_field"] == "custom_value"
assert "existing_meta" in serialized.metadata
assert serialized.metadata["existing_meta"] == "meta_value"
# Тип должен быть именем кастомного класса
assert serialized.type == "CustomEntity"
def test_deserialize_custom_entity(
self, serialized_custom_entity: LinkerEntity
):
"""Тест десериализации в кастомный тип."""
# Используем класс CustomEntity для десериализации, так как он зарегистрирован
deserialized = LinkerEntity._deserialize(serialized_custom_entity)
assert isinstance(deserialized, CustomEntity)
assert deserialized.id == serialized_custom_entity.id
assert deserialized.name == serialized_custom_entity.name
assert deserialized.text == serialized_custom_entity.text
# Проверяем восстановление кастомного поля
assert deserialized.custom_field == "custom_value"
# Проверяем восстановление исходных метаданных
assert "existing_meta" in deserialized.metadata
assert deserialized.metadata["existing_meta"] == "meta_value"
assert deserialized.type == "CustomEntity" # Тип сохраняется
def test_deserialize_base_entity(self, base_entity: LinkerEntity):
"""Тест десериализации базовой сущности (должна вернуться сама)."""
serialized = base_entity.serialize() # Сериализуем базовую
deserialized = LinkerEntity._deserialize(serialized)
assert deserialized is serialized # Возвращается исходный объект LinkerEntity
assert type(deserialized) is LinkerEntity
def test_deserialize_unregistered_type(self):
"""Тест десериализации незарегистрированного типа (должен вернуться исходный объект)."""
unregistered_entity = LinkerEntity(id=uuid4(), type="UnregisteredType")
deserialized = LinkerEntity._deserialize(unregistered_entity)
assert deserialized is unregistered_entity
assert deserialized.type == "UnregisteredType"
def test_deserialize_to_me_on_custom_class(
self, serialized_custom_entity: LinkerEntity
):
"""Тест прямого вызова _deserialize_to_me на кастомном классе."""
# Вызываем метод десериализации непосредственно у CustomEntity
deserialized = CustomEntity._deserialize_to_me(serialized_custom_entity)
assert isinstance(deserialized, CustomEntity)
assert deserialized.id == serialized_custom_entity.id
assert deserialized.custom_field == "custom_value"
assert deserialized.metadata["existing_meta"] == "meta_value"
def test_deserialize_to_me_type_error(self):
"""Тест ошибки TypeError в _deserialize_to_me при неверном типе данных."""
with pytest.raises(TypeError):
# Пытаемся десериализовать не LinkerEntity
CustomEntity._deserialize_to_me("not_an_entity") # type: ignore
def test_register_entity_decorator(self):
"""Тест работы декоратора @register_entity."""
@register_entity
@dataclass
class TempEntity(LinkerEntity):
temp_field: str = "temp"
type: str = "Temporary" # Явно указываем тип для регистрации
assert "Temporary" in LinkerEntity._entity_classes
assert LinkerEntity._entity_classes["Temporary"] is TempEntity
# Проверяем, что он десериализуется
instance = TempEntity(id=uuid4(), name="Temp instance", temp_field="value")
serialized = instance.serialize()
assert serialized.type == "Temporary"
deserialized = LinkerEntity._deserialize(serialized)
assert isinstance(deserialized, TempEntity)
assert deserialized.temp_field == "value"
# Удаляем временный класс из реестра, чтобы не влиять на другие тесты
del LinkerEntity._entity_classes["Temporary"]
assert "Temporary" not in LinkerEntity._entity_classes