如何为带连接状态的Connector类编写独立的unittest单元测试
针对Connector类的单元测试最佳实践方案
首先你当前的测试属于集成测试范畴,依赖真实网络设备、且测试close_connection时强依赖open_connection的实现,不符合单元测试的隔离要求。可以按照以下两类测试拆分处理:
1. 单元测试方案(无外部依赖,测试间完全隔离)
单元测试只验证Connector类自身的逻辑正确性,不需要真实发起网络连接,所有外部依赖(比如netmiko的连接能力、日志组件、自定义异常)全部用Mock模拟即可,完全不需要依赖其他方法的测试结果。
核心实现思路
- 用
unittest.mock模拟netmiko.ConnectHandler,不需要真实设备就能验证参数拼接、异常处理、方法调用逻辑是否符合预期 - 测试
close_connection时直接传入Mock的handler实例,不需要调用open_connection方法
代码示例
import unittest from unittest.mock import patch, MagicMock from your_module import Connector, ConnectionTypeError class TestConnectorUnit(unittest.TestCase): def setUp(self): self.connector = Connector() # 通用的合法参数 self.valid_args = { "device_name" : "test_device", "device_type": "cisco_ios_serial", "username": "test", "password": "test", "secret": "test", "port": "ttyUSB0", "connection_type": "serial" } # 测试open_connection参数校验逻辑 def test_open_connection_missing_device_name(self): args = self.valid_args.copy() del args["device_name"] handler = self.connector.open_connection(**args) self.assertIsNone(handler) # 测试__connect方法的连接类型校验逻辑 def test_connect_invalid_connection_type(self): args = self.valid_args.copy() args["connection_type"] = "invalid" with self.assertRaises(ConnectionTypeError): # 私有方法可以通过_Connector__connect访问 self.connector._Connector__connect(**args) # 测试正常场景下open_connection返回handler @patch("your_module.netmiko.ConnectHandler") def test_open_connection_success(self, mock_connect): # 设置mock的返回值 mock_handler = MagicMock() mock_connect.return_value = mock_handler handler = self.connector.open_connection(**self.valid_args) # 验证ConnectHandler被正确调用 mock_connect.assert_called_once() self.assertEqual(handler, mock_handler) # 独立测试close_connection,不需要调用open_connection def test_close_connection(self): mock_handler = MagicMock() self.connector.close_connection(mock_handler) # 验证handler的disconnect方法被调用 mock_handler.disconnect.assert_called_once() # 还可以单独测试各种异常场景,比如超时、认证失败时的日志和返回是否符合预期 @patch("your_module.netmiko.ConnectHandler") @patch("your_module.console_logger") def test_connect_timeout(self, mock_logger, mock_connect): from netmiko import NetmikoTimeoutException mock_connect.side_effect = NetmikoTimeoutException("timeout") self.connector._Connector__connect(**self.valid_args) mock_logger.info.assert_any_call("[i] Connection timeout. Please check connection parameters and retry. More details in logs.")
2. 集成测试方案(验证真实连接能力)
如果需要验证和真实设备/模拟设备的实际连接效果,属于集成测试范畴,可以按照以下方式保证测试独立性:
- 每个测试单独创建、销毁连接,哪怕会有重复开销,也能保证测试间互不影响
- 如果测试不会修改设备状态,也可以用
setUpClass在所有测试开始前创建一次连接,tearDownClass测试全部结束后销毁,减少重复开销 - 优先用本地模拟的网络设备(比如Cisco的VIRL、EVE-NG镜像,或者netmiko官方的测试模拟服务),避免依赖真实物理设备
内容的提问来源于stack exchange,提问作者user10211997
相关产品推荐
相关产品推荐

