test_interfaces.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. """
  2. 应用层接口单元测试
  3. 测试命令处理器和查询处理器协议的实现。
  4. """
  5. import pytest
  6. from typing import List
  7. from src.application.shared.interfaces import CommandHandler, QueryHandler
  8. # 测试用的命令和查询类(不以Test开头避免被pytest收集)
  9. class SampleCommand:
  10. """示例命令"""
  11. def __init__(self, value: str):
  12. self.value = value
  13. class SampleQuery:
  14. """示例查询"""
  15. def __init__(self, filter_value: str):
  16. self.filter_value = filter_value
  17. class SampleResult:
  18. """示例结果"""
  19. def __init__(self, data: str):
  20. self.data = data
  21. # 具体的处理器实现
  22. class ConcreteCommandHandler:
  23. """具体的命令处理器实现"""
  24. async def handle(self, command: SampleCommand) -> str:
  25. """处理示例命令"""
  26. return f"Processed: {command.value}"
  27. class ConcreteQueryHandler:
  28. """具体的查询处理器实现"""
  29. async def handle(self, query: SampleQuery) -> List[SampleResult]:
  30. """处理示例查询"""
  31. return [SampleResult(f"Result for: {query.filter_value}")]
  32. class TestCommandHandlerProtocol:
  33. """CommandHandler 协议测试"""
  34. @pytest.mark.asyncio
  35. async def test_concrete_handler_implements_protocol(self):
  36. """测试具体处理器实现协议"""
  37. # Arrange
  38. handler = ConcreteCommandHandler()
  39. command = SampleCommand("test_value")
  40. # Act
  41. result = await handler.handle(command)
  42. # Assert
  43. assert result == "Processed: test_value"
  44. @pytest.mark.asyncio
  45. async def test_handler_can_be_used_as_protocol(self):
  46. """测试处理器可以作为协议使用"""
  47. # Arrange
  48. handler: CommandHandler[SampleCommand, str] = ConcreteCommandHandler()
  49. command = SampleCommand("protocol_test")
  50. # Act
  51. result = await handler.handle(command)
  52. # Assert
  53. assert "protocol_test" in result
  54. def test_protocol_has_handle_method(self):
  55. """测试协议有 handle 方法"""
  56. # Arrange
  57. handler = ConcreteCommandHandler()
  58. # Act & Assert
  59. assert hasattr(handler, 'handle')
  60. assert callable(handler.handle)
  61. @pytest.mark.asyncio
  62. async def test_handler_with_different_return_type(self):
  63. """测试处理器可以返回不同类型"""
  64. # Arrange
  65. class IntCommandHandler:
  66. async def handle(self, command: SampleCommand) -> int:
  67. return len(command.value)
  68. handler: CommandHandler[SampleCommand, int] = IntCommandHandler()
  69. command = SampleCommand("12345")
  70. # Act
  71. result = await handler.handle(command)
  72. # Assert
  73. assert result == 5
  74. assert isinstance(result, int)
  75. class TestQueryHandlerProtocol:
  76. """QueryHandler 协议测试"""
  77. @pytest.mark.asyncio
  78. async def test_concrete_handler_implements_protocol(self):
  79. """测试具体处理器实现协议"""
  80. # Arrange
  81. handler = ConcreteQueryHandler()
  82. query = SampleQuery("test_filter")
  83. # Act
  84. results = await handler.handle(query)
  85. # Assert
  86. assert len(results) == 1
  87. assert results[0].data == "Result for: test_filter"
  88. @pytest.mark.asyncio
  89. async def test_handler_can_be_used_as_protocol(self):
  90. """测试处理器可以作为协议使用"""
  91. # Arrange
  92. handler: QueryHandler[SampleQuery, List[SampleResult]] = ConcreteQueryHandler()
  93. query = SampleQuery("protocol_query")
  94. # Act
  95. results = await handler.handle(query)
  96. # Assert
  97. assert len(results) > 0
  98. assert "protocol_query" in results[0].data
  99. def test_protocol_has_handle_method(self):
  100. """测试协议有 handle 方法"""
  101. # Arrange
  102. handler = ConcreteQueryHandler()
  103. # Act & Assert
  104. assert hasattr(handler, 'handle')
  105. assert callable(handler.handle)
  106. @pytest.mark.asyncio
  107. async def test_handler_with_empty_results(self):
  108. """测试处理器可以返回空结果"""
  109. # Arrange
  110. class EmptyQueryHandler:
  111. async def handle(self, query: SampleQuery) -> List[SampleResult]:
  112. return []
  113. handler: QueryHandler[SampleQuery, List[SampleResult]] = EmptyQueryHandler()
  114. query = SampleQuery("no_results")
  115. # Act
  116. results = await handler.handle(query)
  117. # Assert
  118. assert results == []
  119. assert isinstance(results, list)
  120. @pytest.mark.asyncio
  121. async def test_handler_with_dict_return_type(self):
  122. """测试处理器可以返回字典类型"""
  123. # Arrange
  124. class DictQueryHandler:
  125. async def handle(self, query: SampleQuery) -> dict:
  126. return {"filter": query.filter_value, "count": 10}
  127. handler: QueryHandler[SampleQuery, dict] = DictQueryHandler()
  128. query = SampleQuery("dict_test")
  129. # Act
  130. result = await handler.handle(query)
  131. # Assert
  132. assert isinstance(result, dict)
  133. assert result["filter"] == "dict_test"
  134. assert result["count"] == 10
  135. class TestProtocolTypeHints:
  136. """协议类型提示测试"""
  137. def test_command_handler_accepts_generic_types(self):
  138. """测试命令处理器接受泛型类型"""
  139. # Arrange & Act
  140. handler: CommandHandler[SampleCommand, str] = ConcreteCommandHandler()
  141. # Assert
  142. assert handler is not None
  143. def test_query_handler_accepts_generic_types(self):
  144. """测试查询处理器接受泛型类型"""
  145. # Arrange & Act
  146. handler: QueryHandler[SampleQuery, List[SampleResult]] = ConcreteQueryHandler()
  147. # Assert
  148. assert handler is not None
  149. @pytest.mark.asyncio
  150. async def test_handlers_can_be_composed(self):
  151. """测试处理器可以组合使用"""
  152. # Arrange
  153. command_handler: CommandHandler[SampleCommand, str] = ConcreteCommandHandler()
  154. query_handler: QueryHandler[SampleQuery, List[SampleResult]] = ConcreteQueryHandler()
  155. # Act
  156. command_result = await command_handler.handle(SampleCommand("compose_test"))
  157. query_result = await query_handler.handle(SampleQuery("compose_test"))
  158. # Assert
  159. assert "compose_test" in command_result
  160. assert len(query_result) > 0