""" 共享值对象单元测试 测试 EntityId 和 Timestamp 值对象的创建、验证和行为。 """ import pytest from datetime import datetime, timedelta from uuid import UUID, uuid4 from src.domain.shared.value_objects import EntityId, Timestamp class TestEntityId: """EntityId 值对象单元测试""" def test_create_entity_id_with_valid_value(self): """测试使用有效值创建实体 ID""" # Arrange & Act entity_id = EntityId("doc_123") # Assert assert entity_id.value == "doc_123" def test_create_entity_id_with_empty_string_raises_error(self): """测试使用空字符串创建实体 ID 会抛出错误""" # Act & Assert with pytest.raises(ValueError, match="Entity ID cannot be empty"): EntityId("") def test_create_entity_id_with_whitespace_only_raises_error(self): """测试使用仅空格的字符串创建实体 ID 会抛出错误""" # Act & Assert with pytest.raises(ValueError, match="Entity ID cannot be whitespace only"): EntityId(" ") def test_create_entity_id_with_non_string_raises_error(self): """测试使用非字符串值创建实体 ID 会抛出错误""" # Act & Assert with pytest.raises(ValueError, match="Entity ID must be a string"): EntityId(123) # type: ignore def test_generate_creates_unique_id(self): """测试 generate 方法创建唯一 ID""" # Act id1 = EntityId.generate() id2 = EntityId.generate() # Assert assert id1.value != id2.value # 验证是有效的 UUID 格式 UUID(id1.value) UUID(id2.value) def test_from_uuid_creates_entity_id(self): """测试从 UUID 创建实体 ID""" # Arrange uuid_value = uuid4() # Act entity_id = EntityId.from_uuid(uuid_value) # Assert assert entity_id.value == str(uuid_value) def test_entity_id_is_immutable(self): """测试实体 ID 是不可变的""" # Arrange entity_id = EntityId("doc_123") # Act & Assert with pytest.raises(AttributeError): entity_id.value = "doc_456" # type: ignore def test_entity_id_str_representation(self): """测试实体 ID 的字符串表示""" # Arrange entity_id = EntityId("doc_123") # Act & Assert assert str(entity_id) == "doc_123" def test_entity_id_repr_representation(self): """测试实体 ID 的详细表示""" # Arrange entity_id = EntityId("doc_123") # Act & Assert assert repr(entity_id) == "EntityId(value='doc_123')" def test_entity_id_equality(self): """测试实体 ID 的相等性比较""" # Arrange id1 = EntityId("doc_123") id2 = EntityId("doc_123") id3 = EntityId("doc_456") # Act & Assert assert id1 == id2 assert id1 != id3 class TestTimestamp: """Timestamp 值对象单元测试""" def test_create_timestamp_with_valid_datetime(self): """测试使用有效 datetime 创建时间戳""" # Arrange dt = datetime(2025, 1, 15, 10, 30, 0) # Act timestamp = Timestamp(dt) # Assert assert timestamp.value == dt def test_create_timestamp_with_non_datetime_raises_error(self): """测试使用非 datetime 对象创建时间戳会抛出错误""" # Act & Assert with pytest.raises(ValueError, match="Timestamp value must be a datetime object"): Timestamp("2025-01-15") # type: ignore def test_now_creates_current_timestamp(self): """测试 now 方法创建当前时间戳""" # Arrange before = datetime.now() # Act timestamp = Timestamp.now() # Arrange after = datetime.now() # Assert assert before <= timestamp.value <= after def test_from_iso_string_creates_timestamp(self): """测试从 ISO 字符串创建时间戳""" # Arrange iso_string = "2025-01-15T10:30:00" # Act timestamp = Timestamp.from_iso_string(iso_string) # Assert assert timestamp.value == datetime(2025, 1, 15, 10, 30, 0) def test_from_iso_string_with_invalid_format_raises_error(self): """测试从无效 ISO 字符串创建时间戳会抛出错误""" # Act & Assert with pytest.raises(ValueError, match="Invalid ISO timestamp string"): Timestamp.from_iso_string("invalid-date") def test_to_iso_string_converts_to_iso_format(self): """测试转换为 ISO 字符串""" # Arrange dt = datetime(2025, 1, 15, 10, 30, 0) timestamp = Timestamp(dt) # Act iso_string = timestamp.to_iso_string() # Assert assert iso_string == "2025-01-15T10:30:00" def test_is_before_returns_true_for_earlier_timestamp(self): """测试 is_before 对于更早的时间戳返回 True""" # Arrange ts1 = Timestamp(datetime(2025, 1, 15, 10, 0, 0)) ts2 = Timestamp(datetime(2025, 1, 15, 11, 0, 0)) # Act & Assert assert ts1.is_before(ts2) assert not ts2.is_before(ts1) def test_is_after_returns_true_for_later_timestamp(self): """测试 is_after 对于更晚的时间戳返回 True""" # Arrange ts1 = Timestamp(datetime(2025, 1, 15, 10, 0, 0)) ts2 = Timestamp(datetime(2025, 1, 15, 11, 0, 0)) # Act & Assert assert ts2.is_after(ts1) assert not ts1.is_after(ts2) def test_timestamp_is_immutable(self): """测试时间戳是不可变的""" # Arrange timestamp = Timestamp.now() # Act & Assert with pytest.raises(AttributeError): timestamp.value = datetime.now() # type: ignore def test_timestamp_str_representation(self): """测试时间戳的字符串表示""" # Arrange dt = datetime(2025, 1, 15, 10, 30, 0) timestamp = Timestamp(dt) # Act & Assert assert str(timestamp) == "2025-01-15T10:30:00" def test_timestamp_repr_representation(self): """测试时间戳的详细表示""" # Arrange dt = datetime(2025, 1, 15, 10, 30, 0) timestamp = Timestamp(dt) # Act & Assert assert "Timestamp(value=" in repr(timestamp) def test_timestamp_equality(self): """测试时间戳的相等性比较""" # Arrange dt = datetime(2025, 1, 15, 10, 30, 0) ts1 = Timestamp(dt) ts2 = Timestamp(dt) ts3 = Timestamp(dt + timedelta(seconds=1)) # Act & Assert assert ts1 == ts2 assert ts1 != ts3 def test_timestamp_comparison_operators(self): """测试时间戳的比较运算符""" # Arrange ts1 = Timestamp(datetime(2025, 1, 15, 10, 0, 0)) ts2 = Timestamp(datetime(2025, 1, 15, 11, 0, 0)) ts3 = Timestamp(datetime(2025, 1, 15, 11, 0, 0)) # Act & Assert assert ts1 < ts2 assert ts1 <= ts2 assert ts2 > ts1 assert ts2 >= ts1 assert ts2 <= ts3 assert ts2 >= ts3 def test_timestamp_equality_with_non_timestamp_returns_false(self): """测试时间戳与非时间戳对象比较返回 False""" # Arrange timestamp = Timestamp.now() # Act & Assert assert timestamp != "not a timestamp" assert timestamp != 123 assert timestamp != None