test_approve_order.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. """
  2. 测试 approve_order 功能
  3. 测试场景:
  4. 1. 验证 extract_output_domain_and_logic 方法能正确提取输出域和处理逻辑
  5. 2. 验证 generate_order_resources 方法能正确创建资源
  6. 3. 验证 approve_order 完整流程
  7. """
  8. import json
  9. from unittest.mock import MagicMock, patch
  10. import pytest
  11. class TestExtractOutputDomainAndLogic:
  12. """测试 extract_output_domain_and_logic 方法"""
  13. @patch("app.core.data_service.data_product_service.current_app")
  14. @patch("app.core.data_service.data_product_service.OpenAI")
  15. def test_extract_success(self, mock_openai, mock_app):
  16. """测试成功提取输出域和处理逻辑"""
  17. from app.core.data_service.data_product_service import DataOrderService
  18. # 模拟配置
  19. mock_app.config.get.side_effect = lambda key: {
  20. "LLM_API_KEY": "test-key",
  21. "LLM_BASE_URL": "http://test-url",
  22. "LLM_MODEL_NAME": "test-model",
  23. }.get(key)
  24. # 模拟 LLM 响应
  25. mock_response = MagicMock()
  26. mock_response.choices = [MagicMock()]
  27. mock_response.choices[0].message.content = json.dumps(
  28. {
  29. "output_domain": {
  30. "name_zh": "会员消费分析报表",
  31. "name_en": "member_consumption_analysis",
  32. "describe": "汇总会员消费数据的分析报表",
  33. },
  34. "processing_logic": "1. 从会员表提取会员ID、姓名;2. 从消费记录表提取消费金额;3. 按会员汇总消费总额",
  35. }
  36. )
  37. mock_openai.return_value.chat.completions.create.return_value = mock_response
  38. # 执行测试
  39. result = DataOrderService.extract_output_domain_and_logic(
  40. description="我需要一个会员消费分析报表,统计每个会员的消费总额",
  41. input_domains=[{"name_zh": "会员表"}, {"name_zh": "消费记录表"}],
  42. )
  43. # 验证结果
  44. assert "output_domain" in result
  45. assert result["output_domain"]["name_zh"] == "会员消费分析报表"
  46. assert result["output_domain"]["name_en"] == "member_consumption_analysis"
  47. assert "processing_logic" in result
  48. assert "消费" in result["processing_logic"]
  49. @patch("app.core.data_service.data_product_service.current_app")
  50. @patch("app.core.data_service.data_product_service.OpenAI")
  51. def test_extract_with_markdown_response(self, mock_openai, mock_app):
  52. """测试 LLM 返回带 markdown 代码块的响应"""
  53. from app.core.data_service.data_product_service import DataOrderService
  54. mock_app.config.get.side_effect = lambda key: {
  55. "LLM_API_KEY": "test-key",
  56. "LLM_BASE_URL": "http://test-url",
  57. "LLM_MODEL_NAME": "test-model",
  58. }.get(key)
  59. # 模拟带 markdown 代码块的响应
  60. mock_response = MagicMock()
  61. mock_response.choices = [MagicMock()]
  62. mock_response.choices[0].message.content = """```json
  63. {
  64. "output_domain": {
  65. "name_zh": "销售报表",
  66. "name_en": "sales_report",
  67. "describe": "销售数据汇总"
  68. },
  69. "processing_logic": "汇总销售数据"
  70. }
  71. ```"""
  72. mock_openai.return_value.chat.completions.create.return_value = mock_response
  73. result = DataOrderService.extract_output_domain_and_logic(
  74. description="生成销售报表"
  75. )
  76. assert result["output_domain"]["name_zh"] == "销售报表"
  77. @patch("app.core.data_service.data_product_service.current_app")
  78. @patch("app.core.data_service.data_product_service.OpenAI")
  79. def test_extract_fallback_on_error(self, mock_openai, mock_app):
  80. """测试 LLM 调用失败时的回退逻辑"""
  81. from app.core.data_service.data_product_service import DataOrderService
  82. mock_app.config.get.side_effect = lambda key: {
  83. "LLM_API_KEY": "test-key",
  84. "LLM_BASE_URL": "http://test-url",
  85. "LLM_MODEL_NAME": "test-model",
  86. }.get(key)
  87. # 模拟 LLM 调用异常
  88. mock_openai.return_value.chat.completions.create.side_effect = Exception(
  89. "LLM 服务不可用"
  90. )
  91. result = DataOrderService.extract_output_domain_and_logic(
  92. description="测试描述内容"
  93. )
  94. # 验证回退到默认值
  95. assert result["output_domain"]["name_zh"] == "数据产品"
  96. assert result["output_domain"]["name_en"] == "data_product"
  97. assert result["processing_logic"] == "测试描述内容"
  98. assert "error" in result
  99. class TestGenerateOrderResources:
  100. """测试 generate_order_resources 方法"""
  101. @patch("app.core.data_service.data_product_service.db")
  102. @patch("app.core.data_service.data_product_service.neo4j_driver")
  103. @patch.object(
  104. __import__(
  105. "app.core.data_service.data_product_service", fromlist=["DataOrderService"]
  106. ).DataOrderService,
  107. "extract_output_domain_and_logic",
  108. )
  109. def test_generate_resources_creates_all_components(
  110. self, mock_extract, mock_neo4j, mock_db
  111. ):
  112. """测试 generate_order_resources 创建所有必要的组件"""
  113. from app.core.data_service.data_product_service import DataOrderService
  114. from app.models.data_product import DataOrder
  115. # 模拟 LLM 提取结果
  116. mock_extract.return_value = {
  117. "output_domain": {
  118. "name_zh": "测试数据产品",
  119. "name_en": "test_data_product",
  120. "describe": "测试描述",
  121. },
  122. "processing_logic": "测试处理逻辑",
  123. }
  124. # 模拟订单对象
  125. mock_order = MagicMock(spec=DataOrder)
  126. mock_order.id = 1
  127. mock_order.order_no = "DO20240101001"
  128. mock_order.title = "测试订单"
  129. mock_order.description = "测试描述"
  130. mock_order.extraction_purpose = "测试用途"
  131. mock_order.extracted_fields = ["字段1", "字段2"]
  132. mock_order.graph_analysis = {
  133. "matched_domains": [
  134. {"id": 100, "name_zh": "源表1"},
  135. {"id": 101, "name_zh": "源表2"},
  136. ]
  137. }
  138. # 模拟 Neo4j session
  139. mock_session = MagicMock()
  140. mock_neo4j.get_session.return_value.__enter__ = MagicMock(
  141. return_value=mock_session
  142. )
  143. mock_neo4j.get_session.return_value.__exit__ = MagicMock(return_value=False)
  144. # 模拟创建 BusinessDomain 返回 ID
  145. mock_bd_result = MagicMock()
  146. mock_bd_result.__getitem__ = lambda self, key: 200 if key == "bd_id" else None
  147. mock_session.run.return_value.single.side_effect = [
  148. mock_bd_result, # 创建 BusinessDomain
  149. MagicMock(
  150. __getitem__=lambda self, key: 300 if key == "df_id" else None
  151. ), # 创建 DataFlow
  152. ]
  153. # 模拟 task_list 插入
  154. mock_db.session.execute.return_value.fetchone.return_value = (1,)
  155. # 执行测试
  156. result = DataOrderService.generate_order_resources(mock_order)
  157. # 验证结果
  158. assert result["target_business_domain_id"] == 200
  159. assert result["dataflow_id"] == 300
  160. assert result["input_domain_ids"] == [100, 101]
  161. assert "task_id" in result
  162. # 验证 LLM 提取被调用
  163. mock_extract.assert_called_once()
  164. class TestApproveOrderFlow:
  165. """测试完整的 approve_order 流程"""
  166. def test_approve_order_status_validation(self):
  167. """测试订单状态验证"""
  168. # 这个测试需要在实际环境中运行
  169. # 这里只提供测试框架
  170. pass
  171. def test_approve_order_success_flow(self):
  172. """测试审批成功的完整流程"""
  173. # 这个测试需要在实际环境中运行
  174. # 这里只提供测试框架
  175. pass
  176. if __name__ == "__main__":
  177. pytest.main([__file__, "-v"])