test_app.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import pytest
  2. import sys
  3. import os
  4. from unittest.mock import MagicMock, patch
  5. from flask import json
  6. from flask_socketio import SocketIOTestClient
  7. # 添加项目根目录到Python路径
  8. sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  9. from app import app, socketio, serial_client, mqtt_client
  10. class TestApp:
  11. def setup_method(self):
  12. """每个测试方法执行前的设置"""
  13. # 创建Flask测试客户端
  14. self.client = app.test_client()
  15. app.config['TESTING'] = True
  16. # 创建SocketIO测试客户端
  17. self.socketio_client = SocketIOTestClient(app, socketio)
  18. # 模拟串口客户端和MQTT客户端
  19. self.mock_serial = patch('app.serial_client').start()
  20. self.mock_mqtt = patch('app.mqtt_client').start()
  21. # 模拟初始状态
  22. self.mock_serial.get_status.return_value = False
  23. self.mock_mqtt.get_status.return_value = False
  24. def teardown_method(self):
  25. """每个测试方法执行后的清理"""
  26. # 停止所有模拟
  27. patch.stopall()
  28. # 断开SocketIO连接
  29. self.socketio_client.disconnect()
  30. def test_serial_connect_api(self):
  31. """测试串口连接API"""
  32. # 模拟连接成功
  33. self.mock_serial.connect.return_value = (True, "串口连接成功")
  34. # 发送POST请求
  35. response = self.client.post('/api/serial/connect',
  36. data=json.dumps({
  37. 'port': 'COM1',
  38. 'baudrate': 9600
  39. }),
  40. content_type='application/json')
  41. # 验证响应
  42. assert response.status_code == 200
  43. data = json.loads(response.data)
  44. assert data['success'] is True
  45. assert data['message'] == "串口连接成功"
  46. # 验证调用
  47. self.mock_serial.connect.assert_called_once_with('COM1', 9600)
  48. def test_serial_disconnect_api(self):
  49. """测试串口断开连接API"""
  50. # 发送POST请求
  51. response = self.client.post('/api/serial/disconnect')
  52. # 验证响应
  53. assert response.status_code == 200
  54. data = json.loads(response.data)
  55. assert data['success'] is True
  56. assert data['message'] == "串口已断开"
  57. # 验证调用
  58. self.mock_serial.disconnect.assert_called_once()
  59. def test_serial_status_api(self):
  60. """测试获取串口状态API"""
  61. # 模拟串口已连接
  62. self.mock_serial.get_status.return_value = True
  63. # 发送GET请求
  64. response = self.client.get('/api/serial/status')
  65. # 验证响应
  66. assert response.status_code == 200
  67. data = json.loads(response.data)
  68. assert data['connected'] is True
  69. def test_serial_send_api(self):
  70. """测试串口发送数据API"""
  71. # 模拟发送成功
  72. self.mock_serial.send_data.return_value = (True, "数据发送成功")
  73. # 发送POST请求
  74. response = self.client.post('/api/serial/send',
  75. data=json.dumps({
  76. 'data': 'test message'
  77. }),
  78. content_type='application/json')
  79. # 验证响应
  80. assert response.status_code == 200
  81. data = json.loads(response.data)
  82. assert data['success'] is True
  83. # 验证调用
  84. self.mock_serial.send_data.assert_called_once_with('test message')
  85. def test_mqtt_connect_api(self):
  86. """测试MQTT连接API"""
  87. # 模拟连接成功
  88. self.mock_mqtt.connect.return_value = (True, "MQTT连接成功")
  89. # 发送POST请求
  90. mqtt_config = {
  91. 'broker': 'localhost',
  92. 'port': 1883,
  93. 'username': '',
  94. 'password': '',
  95. 'client_id': 'test_client',
  96. 'keepalive': 60,
  97. 'use_tls': False
  98. }
  99. response = self.client.post('/api/mqtt/connect',
  100. data=json.dumps(mqtt_config),
  101. content_type='application/json')
  102. # 验证响应
  103. assert response.status_code == 200
  104. data = json.loads(response.data)
  105. assert data['success'] is True
  106. assert data['message'] == "MQTT连接成功"
  107. # 验证调用
  108. self.mock_mqtt.connect.assert_called_once_with(mqtt_config)
  109. def test_mqtt_disconnect_api(self):
  110. """测试MQTT断开连接API"""
  111. # 发送POST请求
  112. response = self.client.post('/api/mqtt/disconnect')
  113. # 验证响应
  114. assert response.status_code == 200
  115. data = json.loads(response.data)
  116. assert data['success'] is True
  117. assert data['message'] == "MQTT已断开"
  118. # 验证调用
  119. self.mock_mqtt.disconnect.assert_called_once()
  120. def test_mqtt_status_api(self):
  121. """测试获取MQTT状态API"""
  122. # 模拟MQTT已连接
  123. self.mock_mqtt.get_status.return_value = True
  124. # 发送GET请求
  125. response = self.client.get('/api/mqtt/status')
  126. # 验证响应
  127. assert response.status_code == 200
  128. data = json.loads(response.data)
  129. assert data['connected'] is True
  130. def test_mqtt_publish_api(self):
  131. """测试MQTT发布消息API"""
  132. # 模拟发布成功
  133. self.mock_mqtt.publish.return_value = (True, "消息发布成功")
  134. # 发送POST请求
  135. response = self.client.post('/api/mqtt/publish',
  136. data=json.dumps({
  137. 'topic': 'test/topic',
  138. 'message': 'test message'
  139. }),
  140. content_type='application/json')
  141. # 验证响应
  142. assert response.status_code == 200
  143. data = json.loads(response.data)
  144. assert data['success'] is True
  145. # 验证调用
  146. self.mock_mqtt.publish.assert_called_once_with('test/topic', 'test message')
  147. def test_mqtt_subscribe_api(self):
  148. """测试MQTT订阅主题API"""
  149. # 模拟订阅成功
  150. self.mock_mqtt.subscribe.return_value = (True, "主题订阅成功")
  151. # 发送POST请求
  152. response = self.client.post('/api/mqtt/subscribe',
  153. data=json.dumps({
  154. 'topic': 'test/topic'
  155. }),
  156. content_type='application/json')
  157. # 验证响应
  158. assert response.status_code == 200
  159. data = json.loads(response.data)
  160. assert data['success'] is True
  161. # 验证调用
  162. self.mock_mqtt.subscribe.assert_called_once_with('test/topic')
  163. def test_get_serial_data_api(self):
  164. """测试获取串口数据API"""
  165. # 发送GET请求
  166. response = self.client.get('/api/data/serial')
  167. # 验证响应
  168. assert response.status_code == 200
  169. data = json.loads(response.data)
  170. assert isinstance(data, list)
  171. def test_get_mqtt_data_api(self):
  172. """测试获取MQTT数据API"""
  173. # 发送GET请求
  174. response = self.client.get('/api/data/mqtt')
  175. # 验证响应
  176. assert response.status_code == 200
  177. data = json.loads(response.data)
  178. assert isinstance(data, list)
  179. def test_forward_config_api(self):
  180. """测试设置转发配置API"""
  181. # 发送POST请求
  182. response = self.client.post('/api/forward/config',
  183. data=json.dumps({
  184. 'serial_to_mqtt': True,
  185. 'mqtt_to_serial': False,
  186. 'publish_topic': 'serial/data'
  187. }),
  188. content_type='application/json')
  189. # 验证响应
  190. assert response.status_code == 200
  191. data = json.loads(response.data)
  192. assert data['success'] is True
  193. assert data['message'] == "转发配置已更新"
  194. def test_get_forward_status_api(self):
  195. """测试获取转发状态API"""
  196. # 发送GET请求
  197. response = self.client.get('/api/forward/status')
  198. # 验证响应
  199. assert response.status_code == 200
  200. data = json.loads(response.data)
  201. assert 'serial_to_mqtt' in data
  202. assert 'mqtt_to_serial' in data
  203. assert 'publish_topic' in data
  204. def test_health_check_api(self):
  205. """测试健康检查API"""
  206. # 发送GET请求
  207. response = self.client.get('/api/health')
  208. # 验证响应
  209. assert response.status_code == 200
  210. data = json.loads(response.data)
  211. assert data['status'] == 'healthy'
  212. assert 'timestamp' in data
  213. assert 'services' in data
  214. def test_socketio_data_namespace(self):
  215. """测试数据命名空间的WebSocket连接"""
  216. # 连接到数据命名空间
  217. self.socketio_client.connect(namespace='/data')
  218. # 验证连接成功
  219. received = self.socketio_client.get_received('/data')
  220. # 应该收到历史数据事件
  221. events = [event['name'] for event in received]
  222. assert 'serial_data_history' in events or 'mqtt_data_history' in events
  223. # 断开连接
  224. self.socketio_client.disconnect(namespace='/data')
  225. def test_socketio_status_namespace(self):
  226. """测试状态命名空间的WebSocket连接"""
  227. # 连接到状态命名空间
  228. self.socketio_client.connect(namespace='/status')
  229. # 验证连接成功
  230. received = self.socketio_client.get_received('/status')
  231. # 应该收到当前状态事件
  232. events = [event['name'] for event in received]
  233. assert 'serial_status' in events
  234. assert 'mqtt_status' in events
  235. assert 'forward_status' in events
  236. # 断开连接
  237. self.socketio_client.disconnect(namespace='/status')
  238. if __name__ == "__main__":
  239. pytest.main(["-v", __file__])