智慧水务管理系统 - 精河县供水工程综合管理平台

test_inspection_management.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. """
  2. 巡检管理核心流程单元测试
  3. 覆盖任务创建、分配、执行和上报流程
  4. """
  5. import unittest
  6. from unittest.mock import Mock, patch, MagicMock
  7. from datetime import datetime, timedelta
  8. import json
  9. from src.inspection.models import InspectionTask, InspectionReport
  10. from src.inspection.services import TaskService, ExecutionService, ReportService
  11. class TestInspectionTask(unittest.TestCase):
  12. """巡检任务模型测试"""
  13. def setUp(self):
  14. self.task_data = {
  15. "task_id": "inspection_001",
  16. "title": "设备巡检任务",
  17. "description": "检查所有传感器设备状态",
  18. "device_ids": ["sensor_001", "sensor_002", "sensor_003"],
  19. "assigned_to": "inspector_01",
  20. "scheduled_time": "2026-06-17T09:00:00Z",
  21. "duration_minutes": 60,
  22. "priority": "high",
  23. "status": "pending"
  24. }
  25. def test_task_creation(self):
  26. """测试任务创建"""
  27. task = InspectionTask(self.task_data)
  28. self.assertEqual(task.task_id, self.task_data["task_id"])
  29. self.assertEqual(task.title, self.task_data["title"])
  30. self.assertEqual(len(task.device_ids), 3)
  31. self.assertEqual(task.status, "pending")
  32. # 验证时间格式
  33. self.assertTrue(datetime.fromisoformat(task.scheduled_time))
  34. def test_task_validation(self):
  35. """测试任务验证"""
  36. valid_task = InspectionTask(self.task_data)
  37. result = valid_task.validate()
  38. self.assertTrue(result["valid"])
  39. # 测试无效任务
  40. invalid_task_data = self.task_data.copy()
  41. invalid_task_data["device_ids"] = [] # 空设备列表
  42. invalid_task = InspectionTask(invalid_task_data)
  43. result = invalid_task.validate()
  44. self.assertFalse(result["valid"])
  45. def test_task_status_transitions(self):
  46. """测试任务状态转换"""
  47. task = InspectionTask(self.task_data)
  48. # 从pending到assigned
  49. task.assign_to("inspector_02")
  50. self.assertEqual(task.status, "assigned")
  51. self.assertEqual(task.assigned_to, "inspector_02")
  52. # 从assigned到in_progress
  53. task.start_execution()
  54. self.assertEqual(task.status, "in_progress")
  55. self.assertIsNotNone(task.started_at)
  56. # 从in_progress到completed
  57. task.complete_execution()
  58. self.assertEqual(task.status, "completed")
  59. self.assertIsNotNone(task.completed_at)
  60. class TestTaskService(unittest.TestCase):
  61. """任务服务测试"""
  62. def setUp(self):
  63. self.task_service = TaskService()
  64. @patch('src.inspection.services.session')
  65. def test_create_inspection_task(self, mock_session):
  66. """测试创建巡检任务"""
  67. task_data = {
  68. "task_id": "inspection_001",
  69. "title": "设备巡检",
  70. "device_ids": ["sensor_001", "sensor_002"],
  71. "scheduled_time": "2026-06-17T09:00:00Z"
  72. }
  73. with patch.object(self.task_service, 'save_task') as mock_save:
  74. mock_save.return_value = {"success": True, "task_id": "inspection_001"}
  75. result = self.task_service.create_task(task_data)
  76. self.assertTrue(result["success"])
  77. mock_save.assert_called_once()
  78. @patch('src.inspection.services.session')
  79. def test_assign_task(self, mock_session):
  80. """测试任务分配"""
  81. task_id = "inspection_001"
  82. inspector_id = "inspector_01"
  83. with patch.object(self.task_service, 'update_task') as mock_update:
  84. mock_update.return_value = {"success": True}
  85. result = self.task_service.assign_task(task_id, inspector_id)
  86. self.assertTrue(result["success"])
  87. mock_update.assert_called_once()
  88. @patch('src.inspection.services.session')
  89. def test_get_pending_tasks(self, mock_session):
  90. """测试获取待处理任务"""
  91. with patch.object(self.task_service, 'query_tasks') as mock_query:
  92. mock_query.return_value = [
  93. {"task_id": "task_001", "status": "pending"},
  94. {"task_id": "task_002", "status": "pending"}
  95. ]
  96. tasks = self.task_service.get_pending_tasks()
  97. self.assertEqual(len(tasks), 2)
  98. mock_query.assert_called_with(status="pending")
  99. def test_task_scheduling_conflict(self):
  100. """测试任务调度冲突检测"""
  101. task1 = {
  102. "task_id": "task_001",
  103. "scheduled_time": "2026-06-17T09:00:00Z",
  104. "duration_minutes": 60
  105. }
  106. task2 = {
  107. "task_id": "task_002",
  108. "scheduled_time": "2026-06-17T09:30:00Z",
  109. "duration_minutes": 60
  110. }
  111. # 这两个任务有时间冲突
  112. has_conflict = self.task_service.check_scheduling_conflict(task1, task2)
  113. self.assertTrue(has_conflict)
  114. # 不冲突的任务
  115. task3 = {
  116. "task_id": "task_003",
  117. "scheduled_time": "2026-06-17T11:00:00Z",
  118. "duration_minutes": 60
  119. }
  120. has_conflict = self.task_service.check_scheduling_conflict(task1, task3)
  121. self.assertFalse(has_conflict)
  122. class TestExecutionService(unittest.TestCase):
  123. """执行服务测试"""
  124. def setUp(self):
  125. self.execution_service = ExecutionService()
  126. @patch('src.inspection.services.DeviceService')
  127. def test_start_inspection_execution(self, mock_device_service):
  128. """测试开始巡检执行"""
  129. task_id = "inspection_001"
  130. inspector_id = "inspector_01"
  131. mock_device_service.return_value.check_device_availability.return_value = True
  132. result = self.execution_service.start_execution(task_id, inspector_id)
  133. self.assertTrue(result["success"])
  134. self.assertEqual(result["status"], "in_progress")
  135. @patch('src.inspection.services.DeviceService')
  136. def test_inspection_execution_flow(self, mock_device_service):
  137. """测试巡检执行流程"""
  138. task_id = "inspection_001"
  139. # 模拟设备检查
  140. mock_device_service.return_value.check_device_availability.return_value = True
  141. mock_device_service.return_value.perform_diagnostic.return_value = {
  142. "status": "normal",
  143. "metrics": {"temperature": 25.5, "humidity": 60.2}
  144. }
  145. # 执行巡检
  146. execution_result = self.execution_service.execute_inspection(task_id)
  147. self.assertTrue(execution_result["success"])
  148. self.assertIn("device_results", execution_result)
  149. self.assertIn("execution_time", execution_result)
  150. def test_inspection_timeout_handling(self):
  151. """测试巡检超时处理"""
  152. task_id = "inspection_001"
  153. # 模拟长时间运行的巡检
  154. with patch.object(self.execution_service, 'execute_inspection') as mock_execute:
  155. mock_execute.return_value = {
  156. "success": False,
  157. "error": "Execution timeout",
  158. "timeout_seconds": 300
  159. }
  160. result = self.execution_service.execute_inspection(task_id, timeout_seconds=30)
  161. self.assertFalse(result["success"])
  162. self.assertIn("timeout", result["error"])
  163. class TestReportService(unittest.TestCase):
  164. """报告服务测试"""
  165. def setUp(self):
  166. self.report_service = ReportService()
  167. @patch('src.inspection.services.session')
  168. def test_create_inspection_report(self, mock_session):
  169. """测试创建巡检报告"""
  170. task_id = "inspection_001"
  171. report_data = {
  172. "summary": "设备巡检完成",
  173. "findings": [
  174. {"device_id": "sensor_001", "status": "normal", "notes": "运行正常"},
  175. {"device_id": "sensor_002", "status": "warning", "notes": "温度偏高"}
  176. ],
  177. "recommendations": ["建议检查散热系统"]
  178. }
  179. with patch.object(self.report_service, 'save_report') as mock_save:
  180. mock_save.return_value = {"success": True, "report_id": "report_001"}
  181. result = self.report_service.create_report(task_id, report_data)
  182. self.assertTrue(result["success"])
  183. mock_save.assert_called_once()
  184. @patch('src.inspection.services.session')
  185. def test_get_inspection_history(self, mock_session):
  186. """测试获取巡检历史"""
  187. inspector_id = "inspector_01"
  188. start_date = "2026-06-01"
  189. end_date = "2026-06-16"
  190. with patch.object(self.report_service, 'query_reports') as mock_query:
  191. mock_query.return_value = [
  192. {"task_id": "task_001", "date": "2026-06-15", "status": "completed"},
  193. {"task_id": "task_002", "date": "2026-06-14", "status": "completed"}
  194. ]
  195. reports = self.report_service.get_inspection_history(
  196. inspector_id, start_date, end_date
  197. )
  198. self.assertEqual(len(reports), 2)
  199. mock_query.assert_called_with(inspector_id, start_date, end_date)
  200. def test_report_validation(self):
  201. """测试报告验证"""
  202. report_data = {
  203. "task_id": "inspection_001",
  204. "summary": "巡检完成",
  205. "findings": [
  206. {"device_id": "sensor_001", "status": "normal"},
  207. {"device_id": "sensor_002", "status": "warning"}
  208. ]
  209. }
  210. result = self.report_service.validate_report(report_data)
  211. self.assertTrue(result["valid"])
  212. # 测试无效报告(缺少必需字段)
  213. invalid_report = {"summary": " incomplete report"}
  214. result = self.report_service.validate_report(invalid_report)
  215. self.assertFalse(result["valid"])
  216. class TestInspectionReport(unittest.TestCase):
  217. """巡检报告模型测试"""
  218. def setUp(self):
  219. self.report_data = {
  220. "report_id": "report_001",
  221. "task_id": "inspection_001",
  222. "inspector_id": "inspector_01",
  223. "summary": "设备巡检完成",
  224. "start_time": "2026-06-17T09:00:00Z",
  225. "end_time": "2026-06-17T10:30:00Z",
  226. "findings": [
  227. {"device_id": "sensor_001", "status": "normal", "notes": "运行正常"},
  228. {"device_id": "sensor_002", "status": "warning", "notes": "温度偏高"}
  229. ],
  230. "recommendations": ["检查散热系统", "校准传感器"],
  231. "overall_status": "warning"
  232. }
  233. def test_report_creation(self):
  234. """测试报告创建"""
  235. report = InspectionReport(self.report_data)
  236. self.assertEqual(report.report_id, self.report_data["report_id"])
  237. self.assertEqual(report.task_id, self.report_data["task_id"])
  238. self.assertEqual(len(report.findings), 2)
  239. self.assertEqual(report.overall_status, "warning")
  240. # 验证时间
  241. self.assertTrue(datetime.fromisoformat(report.start_time))
  242. self.assertTrue(datetime.fromisoformat(report.end_time))
  243. def test_report_status_calculation(self):
  244. """测试报告状态计算"""
  245. report = InspectionReport(self.report_data)
  246. # 基于发现的问题计算整体状态
  247. calculated_status = report.calculate_overall_status()
  248. self.assertEqual(calculated_status, "warning")
  249. # 修改为正常状态
  250. report.findings = [{"device_id": "sensor_001", "status": "normal"}]
  251. calculated_status = report.calculate_overall_status()
  252. self.assertEqual(calculated_status, "normal")
  253. def test_report_export(self):
  254. """测试报告导出"""
  255. report = InspectionReport(self.report_data)
  256. # 导出为JSON
  257. json_export = report.export_to_json()
  258. self.assertEqual(json_export["report_id"], self.report_data["report_id"])
  259. # 导出为CSV
  260. csv_export = report.export_to_csv()
  261. self.assertIn("device_id,status,notes", csv_export)
  262. # 导出为PDF(模拟)
  263. pdf_export = report.export_to_pdf()
  264. self.assertIsNotNone(pdf_export)
  265. self.assertIn("设备巡检报告", pdf_export)
  266. if __name__ == '__main__':
  267. unittest.main()